Release 980601
[wine] / multimedia / midi.c
1 /*
2  * Sample MIDI Wine Driver for Linux
3  *
4  * Copyright 1994 Martin Ayotte
5  */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include "windows.h"
14 #include "ldt.h"
15 #include "multimedia.h"
16 #include "user.h"
17 #include "driver.h"
18 #include "mmsystem.h"
19 #include "xmalloc.h"
20 #include "debug.h"
21
22 static LINUX_MIDIIN     MidiInDev[MAX_MIDIINDRV];
23 static LINUX_MIDIOUT    MidiOutDev[MAX_MIDIOUTDRV];
24 static LINUX_MCIMIDI    MCIMidiDev[MAX_MCIMIDIDRV];
25
26 /* this is the total number of MIDI devices found */
27 int MODM_NUMDEVS = 0;
28
29 /* this structure holds pointers with information for each MIDI
30  * device found.
31  */
32 LPMIDIOUTCAPS16 midiDevices[MAX_MIDIOUTDRV];
33
34 /**************************************************************************
35  *                      MIDI_NotifyClient                       [internal]
36  */
37 static DWORD MIDI_NotifyClient(UINT16 wDevID, WORD wMsg, 
38                                 DWORD dwParam1, DWORD dwParam2)
39 {
40         TRACE(midi,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
41
42         switch (wMsg) {
43         case MOM_OPEN:
44         case MOM_CLOSE:
45         case MOM_DONE:
46           if (wDevID > MAX_MIDIOUTDRV) return MCIERR_INTERNAL;
47           
48           if (MidiOutDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
49                 MidiOutDev[wDevID].midiDesc.dwCallback, 
50                 MidiOutDev[wDevID].wFlags, 
51                 MidiOutDev[wDevID].midiDesc.hMidi, 
52                 wMsg, 
53                 MidiOutDev[wDevID].midiDesc.dwInstance, 
54                 dwParam1, 
55                 dwParam2)) {
56             WARN(midi,"can't notify client !\n");
57             return MMSYSERR_NOERROR;
58           }
59           break;
60
61         case MIM_OPEN:
62         case MIM_CLOSE:
63           if (wDevID > MAX_MIDIINDRV) return MCIERR_INTERNAL;
64           
65         if (MidiInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
66                 MidiInDev[wDevID].midiDesc.dwCallback, MidiInDev[wDevID].wFlags, 
67                 MidiInDev[wDevID].midiDesc.hMidi, wMsg, 
68                 MidiInDev[wDevID].midiDesc.dwInstance, dwParam1, dwParam2)) {
69             WARN(mciwave,"can't notify client !\n");
70                 return MMSYSERR_NOERROR;
71                 }
72           break;
73         }
74         return 0;
75 }
76
77
78 /**************************************************************************
79  *                              MIDI_ReadByte                   [internal]      
80  */
81 static DWORD MIDI_ReadByte(UINT16 wDevID, BYTE *lpbyt)
82 {
83         if (lpbyt != NULL) {
84                 if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)lpbyt,
85                         (long) sizeof(BYTE)) == (long) sizeof(BYTE)) {
86                         return 0;
87                 }
88         }
89         WARN(midi, "error reading wDevID=%04X\n", wDevID);
90         return MCIERR_INTERNAL;
91
92 }
93
94
95 /**************************************************************************
96  *                              MIDI_ReadWord                   [internal]      
97  */
98 static DWORD MIDI_ReadWord(UINT16 wDevID, LPWORD lpw)
99 {
100         BYTE    hibyte, lobyte;
101         if (lpw != NULL) {
102                 if (MIDI_ReadByte(wDevID, &hibyte) == 0) {
103                         if (MIDI_ReadByte(wDevID, &lobyte) == 0) {
104                                 *lpw = ((WORD)hibyte << 8) + lobyte;
105                                 return 0;
106                         }
107                 }
108         }
109         WARN(midi, "error reading wDevID=%04X\n", wDevID);
110         return MCIERR_INTERNAL;
111 }
112
113
114 /**************************************************************************
115  *                              MIDI_ReadLong                   [internal]      
116  */
117 static DWORD MIDI_ReadLong(UINT16 wDevID, LPDWORD lpdw)
118 {
119         WORD    hiword, loword;
120         if (lpdw != NULL) {
121                 if (MIDI_ReadWord(wDevID, &hiword) == 0) {
122                         if (MIDI_ReadWord(wDevID, &loword) == 0) {
123                                 *lpdw = MAKELONG(loword, hiword);
124                                 return 0;
125                         }
126                 }
127         }
128         WARN(midi, "error reading wDevID=%04X\n", wDevID);
129         return MCIERR_INTERNAL;
130 }
131
132
133 /**************************************************************************
134  *                              MIDI_ReadVaryLen                [internal]      
135  */
136 static DWORD MIDI_ReadVaryLen(UINT16 wDevID, LPDWORD lpdw)
137 {
138         BYTE    byte;
139         DWORD   value;
140         if (lpdw == NULL) return MCIERR_INTERNAL;
141         if (MIDI_ReadByte(wDevID, &byte) != 0) {
142                 WARN(midi, "error reading wDevID=%04X\n", wDevID);
143                 return MCIERR_INTERNAL;
144         }
145         value = (DWORD)(byte & 0x7F);
146         while (byte & 0x80) {
147                 if (MIDI_ReadByte(wDevID, &byte) != 0) {
148                         WARN(midi, "error reading wDevID=%04X\n", wDevID);
149                         return MCIERR_INTERNAL;
150                 }
151                 value = (value << 7) + (byte & 0x7F);
152         }
153         *lpdw = value;
154 /*
155         TRACE(midi, "val=%08lX \n", value);
156 */
157         return 0;
158 }
159
160
161 /**************************************************************************
162  *                              MIDI_ReadMThd                   [internal]      
163  */
164 static DWORD MIDI_ReadMThd(UINT16 wDevID, DWORD dwOffset)
165 {
166         DWORD   toberead;
167         FOURCC  fourcc;
168         TRACE(midi, "(%04X, %08lX);\n", wDevID, dwOffset);
169         if (mmioSeek(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
170                 WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
171                 return MCIERR_INTERNAL;
172         }
173         if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
174                 (long) sizeof(FOURCC)) != (long) sizeof(FOURCC))
175                 return MCIERR_INTERNAL;
176         if (MIDI_ReadLong(wDevID, &toberead) != 0)
177                 return MCIERR_INTERNAL;
178         if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].wFormat) != 0)
179                 return MCIERR_INTERNAL;
180         if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTracks) != 0)
181                 return MCIERR_INTERNAL;
182         if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTempo) != 0)
183                 return MCIERR_INTERNAL;
184         TRACE(midi, "toberead=%08lX, wFormat=%04X nTracks=%04X nTempo=%04X\n",
185                 toberead, MCIMidiDev[wDevID].wFormat,
186                 MCIMidiDev[wDevID].nTracks,
187                 MCIMidiDev[wDevID].nTempo);
188         toberead -= 3 * sizeof(WORD);
189 /*
190                 ntrks = read16bit ();
191                 Mf_division = division = read16bit ();
192 */
193         return 0;
194 }
195
196
197 static DWORD MIDI_ReadMTrk(UINT16 wDevID, DWORD dwOffset)
198 {
199         DWORD   toberead;
200         FOURCC  fourcc;
201         if (mmioSeek(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
202                 WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
203                 }
204         if (mmioRead(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
205                 (long) sizeof(FOURCC)) != (long) sizeof(FOURCC)) {
206                 return MCIERR_INTERNAL;
207                 }
208         if (MIDI_ReadLong(wDevID, &toberead) != 0) {
209                 return MCIERR_INTERNAL;
210                 }
211         TRACE(midi, "toberead=%08lX\n", toberead);
212         toberead -= 3 * sizeof(WORD);
213         MCIMidiDev[wDevID].dwTotalLen = toberead;
214         return 0;
215 }
216
217
218 /**************************************************************************
219  *                              MIDI_mciOpen                    [internal]      
220  */
221 static DWORD MIDI_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS16 lpParms)
222 {
223         MIDIOPENDESC    MidiDesc;
224         DWORD           dwRet;
225         DWORD           dwOffset;
226         LPSTR           lpstrElementName;
227         char            str[128];
228
229         TRACE(midi, "(%08lX, %p)\n", dwFlags, lpParms);
230         if (lpParms == NULL) return MCIERR_INTERNAL;
231
232         if (MCIMidiDev[wDevID].nUseCount > 0) {
233                 /* The driver already open on this channel */
234                 /* If the driver was opened shareable before and this open specifies */
235                 /* shareable then increment the use count */
236                 if (MCIMidiDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
237                         ++MCIMidiDev[wDevID].nUseCount;
238                 else
239                         return MCIERR_MUST_USE_SHAREABLE;
240         } else {
241                 MCIMidiDev[wDevID].nUseCount = 1;
242                 MCIMidiDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
243                 MCIMidiDev[wDevID].hMidiHdr = USER_HEAP_ALLOC(sizeof(MIDIHDR));
244         }
245
246         TRACE(midi, "wDevID=%04X\n", wDevID);
247 /*      lpParms->wDeviceID = wDevID;*/
248         TRACE(midi, "lpParms->wDevID=%04X\n", lpParms->wDeviceID);
249         TRACE(midi, "before OPEN_ELEMENT\n");
250         if (dwFlags & MCI_OPEN_ELEMENT) {
251                 lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
252                 TRACE(midi, "MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
253                 if (strlen(lpstrElementName) > 0) {
254                         strcpy(str, lpstrElementName);
255                         CharUpper32A(str);
256                         MCIMidiDev[wDevID].hFile = mmioOpen16(str, NULL, 
257                                 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
258                         if (MCIMidiDev[wDevID].hFile == 0) {
259                                 WARN(midi, "can't find file='%s' !\n", str);
260                                 return MCIERR_FILE_NOT_FOUND;
261                         }
262                 } else 
263                         MCIMidiDev[wDevID].hFile = 0;
264         }
265         TRACE(midi, "hFile=%u\n", MCIMidiDev[wDevID].hFile);
266         memcpy(&MCIMidiDev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS16));
267         MCIMidiDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
268         MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
269         MCIMidiDev[wDevID].dwBeginData = 0;
270         MCIMidiDev[wDevID].dwTotalLen = 0;
271         MidiDesc.hMidi = 0;
272         if (MCIMidiDev[wDevID].hFile != 0) {
273                 MMCKINFO        ckMainRIFF;
274                 if (mmioDescend(MCIMidiDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
275                         return MCIERR_INTERNAL;
276                 }
277                 TRACE(midi,"ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
278                                 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
279                                 ckMainRIFF.cksize);
280                 dwOffset = 0;
281                 if (ckMainRIFF.ckid == mmioFOURCC('R', 'M', 'I', 'D')) {
282                         TRACE(midi, "is a 'RMID' file \n");
283                         dwOffset = ckMainRIFF.dwDataOffset;
284                 }
285                 if (ckMainRIFF.ckid != mmioFOURCC('M', 'T', 'h', 'd')) {
286                         WARN(midi, "unknown format !\n");
287                         return MCIERR_INTERNAL;
288                 }
289                 if (MIDI_ReadMThd(wDevID, dwOffset) != 0) {
290                         WARN(midi, "can't read 'MThd' header \n");
291                         return MCIERR_INTERNAL;
292                 }
293                 dwOffset = mmioSeek(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
294                 if (MIDI_ReadMTrk(wDevID, dwOffset) != 0) {
295                         WARN(midi, "can't read 'MTrk' header \n");
296                         return MCIERR_INTERNAL;
297                 }
298                 dwOffset = mmioSeek(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
299                 MCIMidiDev[wDevID].dwBeginData = dwOffset;
300                 TRACE(midi, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
301                                 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
302                                 ckMainRIFF.cksize);
303         }
304
305         dwRet = modMessage(wDevID, MODM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);
306 /*      dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);*/
307
308         return 0;
309 }
310
311 /**************************************************************************
312  *                              MIDI_mciStop                    [internal]
313  */
314 static DWORD MIDI_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
315 {
316         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
317         if (lpParms == NULL) return MCIERR_INTERNAL;
318         MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
319         TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
320                         &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
321         return 0;
322 }
323
324
325 /**************************************************************************
326  *                              MIDI_mciClose           [internal]
327  */
328 static DWORD MIDI_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
329 {
330         DWORD           dwRet;
331
332         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
333         if (MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
334                 MIDI_mciStop(wDevID, MCI_WAIT, lpParms);
335                 }
336         MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
337         MCIMidiDev[wDevID].nUseCount--;
338         if (MCIMidiDev[wDevID].nUseCount == 0) {
339                 if (MCIMidiDev[wDevID].hFile != 0) {
340                         mmioClose(MCIMidiDev[wDevID].hFile, 0);
341                         MCIMidiDev[wDevID].hFile = 0;
342                         TRACE(midi, "hFile closed !\n");
343                         }
344                 USER_HEAP_FREE(MCIMidiDev[wDevID].hMidiHdr);
345                 dwRet = modMessage(wDevID, MODM_CLOSE, 0, 0L, 0L);
346                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
347 /*
348                 dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
349                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
350 */
351                 }
352         return 0;
353 }
354
355
356 /**************************************************************************
357  *                              MIDI_mciPlay            [internal]
358  */
359 static DWORD MIDI_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
360 {
361         int             count,start,end;
362         LPMIDIHDR       lpMidiHdr;
363         DWORD           dwData,dwRet;
364         LPWORD          ptr;
365
366         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
367         if (MCIMidiDev[wDevID].hFile == 0) {
368                 WARN(midi, "can't find file='%08lx' !\n", 
369                                 (DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
370                 return MCIERR_FILE_NOT_FOUND;
371         }
372         start = 1;              end = 99999;
373         if (dwFlags & MCI_FROM) {
374                 start = lpParms->dwFrom; 
375                 TRACE(midi, "MCI_FROM=%d \n", start);
376         }
377         if (dwFlags & MCI_TO) {
378                 end = lpParms->dwTo;
379                 TRACE(midi, "MCI_TO=%d \n", end);
380         }
381 #if 0
382         if (dwFlags & MCI_NOTIFY) {
383                 TRACE(midi, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
384                 switch(fork()) {
385                 case -1:
386                         WARN(midi, "Can't 'fork' process !\n");
387                         break;
388                 case 0:
389                         TRACE(midi, "process started ! play in background ...\n");
390                         break;
391                 default:
392                         TRACE(midi, "process started ! return to caller...\n");
393                         return 0;
394                 }
395         }
396 #endif
397
398         lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
399
400         lpMidiHdr->lpData = (LPSTR)xmalloc(1200);
401         if (lpMidiHdr->lpData == NULL) return MCIERR_INTERNAL;
402         lpMidiHdr->dwBufferLength = 1024;
403         lpMidiHdr->dwUser = 0L;
404         lpMidiHdr->dwFlags = 0L;
405         dwRet = modMessage(wDevID, MODM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
406
407 /*      TRACE(midi, "after MODM_PREPARE \n"); */
408
409         MCIMidiDev[wDevID].dwStatus = MCI_MODE_PLAY;
410         while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
411                 TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
412                         &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
413
414                 ptr = (LPWORD)lpMidiHdr->lpData;
415                 for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
416                         if (MIDI_ReadVaryLen(wDevID, &dwData) != 0) break;
417                         *ptr = LOWORD(dwData);
418                 }
419 /*
420                 count = mmioRead(MCIMidiDev[wDevID].hFile, lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
421 */
422                 TRACE(midi, "after read count = %d\n",count);
423
424                 if (count < 1) break;
425                 lpMidiHdr->dwBytesRecorded = count;
426                 TRACE(midi, "before MODM_LONGDATA lpMidiHdr=%p dwBytesRecorded=%lu\n",
427                                         lpMidiHdr, lpMidiHdr->dwBytesRecorded);
428                 dwRet = modMessage(wDevID, MODM_LONGDATA, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
429                 if (dwRet != MMSYSERR_NOERROR) {
430                   switch (dwRet) {
431                   case MMSYSERR_NOTENABLED:
432                     return MCIERR_DEVICE_NOT_READY;
433                     
434                   case MIDIERR_NODEVICE:
435                     return MCIERR_INVALID_DEVICE_ID;
436
437                   case MIDIERR_UNPREPARED:
438                     return MCIERR_DRIVER_INTERNAL;
439
440                   case MIDIERR_STILLPLAYING:
441                     return MCIERR_SEQ_PORT_INUSE;
442
443                   case MMSYSERR_INVALPARAM:
444                     return MCIERR_CANNOT_LOAD_DRIVER;
445                   
446                   default:
447                     return MCIERR_DRIVER;
448                   }     
449                 }
450               }
451         dwRet = modMessage(wDevID, MODM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
452         if (lpMidiHdr->lpData != NULL) {
453                 free(lpMidiHdr->lpData);
454                 lpMidiHdr->lpData = NULL;
455         }
456         MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
457         if (dwFlags & MCI_NOTIFY) {
458                 TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
459                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
460                         MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
461         }
462         return 0;
463       }
464
465
466 /**************************************************************************
467  *                              MIDI_mciRecord                  [internal]
468  */
469 static DWORD MIDI_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
470 {
471         int                     start, end;
472         LPMIDIHDR       lpMidiHdr;
473         DWORD           dwRet;
474
475         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
476         if (MCIMidiDev[wDevID].hFile == 0) {
477                 WARN(midi, "can't find file='%08lx' !\n", 
478                         (DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
479                 return MCIERR_FILE_NOT_FOUND;
480         }
481         start = 1;              end = 99999;
482         if (dwFlags & MCI_FROM) {
483                 start = lpParms->dwFrom; 
484                 TRACE(midi, "MCI_FROM=%d \n", start);
485         }
486         if (dwFlags & MCI_TO) {
487                 end = lpParms->dwTo;
488                 TRACE(midi, "MCI_TO=%d \n", end);
489         }
490         lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
491         lpMidiHdr->lpData = (LPSTR) xmalloc(1200);
492         lpMidiHdr->dwBufferLength = 1024;
493         lpMidiHdr->dwUser = 0L;
494         lpMidiHdr->dwFlags = 0L;
495         dwRet = midMessage(wDevID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
496         TRACE(midi, "after MIDM_PREPARE \n");
497         MCIMidiDev[wDevID].dwStatus = MCI_MODE_RECORD;
498         while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
499                 TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
500                         &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
501                 lpMidiHdr->dwBytesRecorded = 0;
502                 dwRet = midMessage(wDevID, MIDM_START, 0, 0L, 0L);
503                 TRACE(midi, "after MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
504                                         lpMidiHdr, lpMidiHdr->dwBytesRecorded);
505                 if (lpMidiHdr->dwBytesRecorded == 0) break;
506         }
507         TRACE(midi, "before MIDM_UNPREPARE \n");
508         dwRet = midMessage(wDevID, MIDM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
509         TRACE(midi, "after MIDM_UNPREPARE \n");
510         if (lpMidiHdr->lpData != NULL) {
511                 free(lpMidiHdr->lpData);
512                 lpMidiHdr->lpData = NULL;
513         }
514         MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
515         if (dwFlags & MCI_NOTIFY) {
516                 TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
517                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
518                         MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
519         }
520         return 0;
521 }
522
523
524 /**************************************************************************
525  *                              MIDI_mciPause                   [internal]
526  */
527 static DWORD MIDI_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
528 {
529         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
530         if (lpParms == NULL) return MCIERR_INTERNAL;
531         return 0;
532 }
533
534
535 /**************************************************************************
536  *                              MIDI_mciResume                  [internal]
537  */
538 static DWORD MIDI_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
539 {
540         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
541         if (lpParms == NULL) return MCIERR_INTERNAL;
542         return 0;
543 }
544
545
546 /**************************************************************************
547  *                              MIDI_mciSet                     [internal]
548  */
549 static DWORD MIDI_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
550 {
551         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
552         if (lpParms == NULL) return MCIERR_INTERNAL;
553         TRACE(midi, "dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
554         TRACE(midi, "dwAudio=%08lX\n", lpParms->dwAudio);
555         if (dwFlags & MCI_SET_TIME_FORMAT) {
556                 switch (lpParms->dwTimeFormat) {
557                 case MCI_FORMAT_MILLISECONDS:
558                         TRACE(midi, "MCI_FORMAT_MILLISECONDS !\n");
559                         break;
560                 case MCI_FORMAT_BYTES:
561                         TRACE(midi, "MCI_FORMAT_BYTES !\n");
562                         break;
563                 case MCI_FORMAT_SAMPLES:
564                         TRACE(midi, "MCI_FORMAT_SAMPLES !\n");
565                         break;
566                 default:
567                         WARN(midi, "bad time format !\n");
568                         return MCIERR_BAD_TIME_FORMAT;
569                 }
570         }
571         if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
572         if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
573         if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
574         if (dwFlags & MCI_SET_AUDIO)
575                 TRACE(midi, "MCI_SET_AUDIO !\n");
576         if (dwFlags && MCI_SET_ON) {
577                 TRACE(midi, "MCI_SET_ON !\n");
578                 if (dwFlags && MCI_SET_AUDIO_LEFT)
579                         TRACE(midi, "MCI_SET_AUDIO_LEFT !\n");
580                 if (dwFlags && MCI_SET_AUDIO_RIGHT)
581                         TRACE(midi, "MCI_SET_AUDIO_RIGHT !\n");
582         }
583         if (dwFlags & MCI_SET_OFF)
584                 TRACE(midi, "MCI_SET_OFF !\n");
585         if (dwFlags & MCI_SEQ_SET_MASTER)
586                 TRACE(midi, "MCI_SEQ_SET_MASTER !\n");
587         if (dwFlags & MCI_SEQ_SET_SLAVE)
588                 TRACE(midi, "MCI_SEQ_SET_SLAVE !\n");
589         if (dwFlags & MCI_SEQ_SET_OFFSET)
590                 TRACE(midi, "MCI_SEQ_SET_OFFSET !\n");
591         if (dwFlags & MCI_SEQ_SET_PORT)
592                 TRACE(midi, "MCI_SEQ_SET_PORT !\n");
593         if (dwFlags & MCI_SEQ_SET_TEMPO)
594                 TRACE(midi, "MCI_SEQ_SET_TEMPO !\n");
595         return 0;
596 }
597
598
599 /**************************************************************************
600  *                              MIDI_mciStatus          [internal]
601  */
602 static DWORD MIDI_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
603 {
604         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
605         if (lpParms == NULL) return MCIERR_INTERNAL;
606         if (dwFlags & MCI_STATUS_ITEM) {
607                 switch(lpParms->dwItem) {
608                 case MCI_STATUS_CURRENT_TRACK:
609                         lpParms->dwReturn = 1;
610                         break;
611                 case MCI_STATUS_LENGTH:
612                         lpParms->dwReturn = 5555;
613                         if (dwFlags & MCI_TRACK) {
614                                 lpParms->dwTrack = 1;
615                                 lpParms->dwReturn = 2222;
616                         }
617                         break;
618                 case MCI_STATUS_MODE:
619                         lpParms->dwReturn = MCI_MODE_STOP;
620                         break;
621                 case MCI_STATUS_MEDIA_PRESENT:
622                         TRACE(midi, "MCI_STATUS_MEDIA_PRESENT !\n");
623                         lpParms->dwReturn = TRUE;
624                         break;
625                 case MCI_STATUS_NUMBER_OF_TRACKS:
626                         lpParms->dwReturn = 1;
627                         break;
628                 case MCI_STATUS_POSITION:
629                         lpParms->dwReturn = 3333;
630                         if (dwFlags & MCI_STATUS_START)
631                                 lpParms->dwItem = 1;
632                         if (dwFlags & MCI_TRACK) {
633                                 lpParms->dwTrack = 1;
634                                 lpParms->dwReturn = 777;
635                         }
636                         break;
637                 case MCI_STATUS_READY:
638                         TRACE(midi, "MCI_STATUS_READY !\n");
639                         lpParms->dwReturn = TRUE;
640                         break;
641                 case MCI_STATUS_TIME_FORMAT:
642                         TRACE(midi, "MCI_STATUS_TIME_FORMAT !\n");
643                         lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
644                         break;
645                 case MCI_SEQ_STATUS_DIVTYPE:
646                         TRACE(midi, "MCI_SEQ_STATUS_DIVTYPE !\n");
647                         lpParms->dwReturn = 0;
648                         break;
649                 case MCI_SEQ_STATUS_MASTER:
650                         TRACE(midi, "MCI_SEQ_STATUS_MASTER !\n");
651                         lpParms->dwReturn = 0;
652                         break;
653                 case MCI_SEQ_STATUS_SLAVE:
654                         TRACE(midi, "MCI_SEQ_STATUS_SLAVE !\n");
655                         lpParms->dwReturn = 0;
656                         break;
657                 case MCI_SEQ_STATUS_OFFSET:
658                         TRACE(midi, "MCI_SEQ_STATUS_OFFSET !\n");
659                         lpParms->dwReturn = 0;
660                         break;
661                 case MCI_SEQ_STATUS_PORT:
662                         TRACE(midi, "MCI_SEQ_STATUS_PORT !\n");
663                         lpParms->dwReturn = 0;
664                         break;
665                 case MCI_SEQ_STATUS_TEMPO:
666                         TRACE(midi, "MCI_SEQ_STATUS_TEMPO !\n");
667                         lpParms->dwReturn = 0;
668                         break;
669                 default:
670                         WARN(midi, "unknowm command %08lX !\n", lpParms->dwItem);
671                         return MCIERR_UNRECOGNIZED_COMMAND;
672                 }
673         }
674         if (dwFlags & MCI_NOTIFY) {
675                 TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
676                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
677                         MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
678         }
679         return 0;
680 }
681
682 /**************************************************************************
683  *                              MIDI_mciGetDevCaps              [internal]
684  */
685 static DWORD MIDI_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
686                                         LPMCI_GETDEVCAPS_PARMS lpParms)
687 {
688         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
689         if (lpParms == NULL) return MCIERR_INTERNAL;
690         if (dwFlags & MCI_GETDEVCAPS_ITEM) {
691                 switch(lpParms->dwItem) {
692                 case MCI_GETDEVCAPS_CAN_RECORD:
693                         lpParms->dwReturn = TRUE;
694                         break;
695                 case MCI_GETDEVCAPS_HAS_AUDIO:
696                         lpParms->dwReturn = TRUE;
697                         break;
698                 case MCI_GETDEVCAPS_HAS_VIDEO:
699                         lpParms->dwReturn = FALSE;
700                         break;
701                 case MCI_GETDEVCAPS_DEVICE_TYPE:
702                         lpParms->dwReturn = MCI_DEVTYPE_SEQUENCER;
703                         break;
704                 case MCI_GETDEVCAPS_USES_FILES:
705                         lpParms->dwReturn = TRUE;
706                         break;
707                 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
708                         lpParms->dwReturn = TRUE;
709                         break;
710                 case MCI_GETDEVCAPS_CAN_EJECT:
711                         lpParms->dwReturn = FALSE;
712                         break;
713                 case MCI_GETDEVCAPS_CAN_PLAY:
714                         lpParms->dwReturn = TRUE;
715                         break;
716                 case MCI_GETDEVCAPS_CAN_SAVE:
717                         lpParms->dwReturn = FALSE;
718                         break;
719                 default:
720                         return MCIERR_UNRECOGNIZED_COMMAND;
721                 }
722         }
723         return 0;
724 }
725
726
727 /**************************************************************************
728  *                              MIDI_mciInfo                    [internal]
729  */
730 static DWORD MIDI_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
731 {
732         TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
733         if (lpParms == NULL) return MCIERR_INTERNAL;
734         lpParms->lpstrReturn = NULL;
735         switch(dwFlags) {
736         case MCI_INFO_PRODUCT:
737                 lpParms->lpstrReturn = "Linux Sound System 0.5";
738                 break;
739         case MCI_INFO_FILE:
740                 lpParms->lpstrReturn = "FileName";
741                 break;
742         default:
743                 return MCIERR_UNRECOGNIZED_COMMAND;
744         }
745         if (lpParms->lpstrReturn != NULL)
746                 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
747         else
748                 lpParms->dwRetSize = 0;
749         return 0;
750 }
751
752
753 /*-----------------------------------------------------------------------*/
754
755
756 /**************************************************************************
757  *                              midGetDevCaps                   [internal]
758  */
759 static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPS16 lpCaps, DWORD dwSize)
760 {
761         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
762         lpCaps->wMid = 0x00FF;          /* Manufac ID */
763         lpCaps->wPid = 0x0001;          /* Product ID */
764         lpCaps->vDriverVersion = 0x001; /* Product Version */
765         strcpy(lpCaps->szPname, "Linux MIDIIN Driver");
766
767         return MMSYSERR_NOERROR;
768 }
769
770 /**************************************************************************
771  *                      midOpen                                 [internal]
772  */
773 static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
774 {
775         int             midi;
776         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
777         if (lpDesc == NULL) {
778                 WARN(midi, "Invalid Parameter !\n");
779                 return MMSYSERR_INVALPARAM;
780         }
781         if (wDevID >= MAX_MIDIINDRV) {
782                 TRACE(midi,"MAX_MIDIINDRV reached !\n");
783                 return MMSYSERR_ALLOCATED;
784         }
785         MidiInDev[wDevID].unixdev = 0;
786         midi = open (MIDI_DEV, O_RDONLY, 0);
787         if (midi == -1) {
788                 WARN(midi,"can't open !\n");
789                 return MMSYSERR_NOTENABLED;
790         }
791         MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
792         switch(MidiInDev[wDevID].wFlags) {
793                 case DCB_NULL:
794                         TRACE(midi,"CALLBACK_NULL !\n");
795                         break;
796                 case DCB_WINDOW:
797                         TRACE(midi, "CALLBACK_WINDOW !\n");
798                         break;
799                 case DCB_TASK:
800                         TRACE(midi, "CALLBACK_TASK !\n");
801                         break;
802                 case DCB_FUNCTION:
803                         TRACE(midi, "CALLBACK_FUNCTION !\n");
804                         break;
805         }
806         MidiInDev[wDevID].lpQueueHdr = NULL;
807         MidiInDev[wDevID].unixdev = midi;
808         MidiInDev[wDevID].dwTotalPlayed = 0;
809         MidiInDev[wDevID].bufsize = 0x3FFF;
810         if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
811                 WARN(midi,"can't notify client !\n");
812                 return MMSYSERR_INVALPARAM;
813         }
814         return MMSYSERR_NOERROR;
815 }
816
817 /**************************************************************************
818  *                      midClose                                [internal]
819  */
820 static DWORD midClose(WORD wDevID)
821 {
822         TRACE(midi, "(%04X);\n", wDevID);
823         if (MidiInDev[wDevID].unixdev == 0) {
824                 WARN(midi,"can't close !\n");
825                 return MMSYSERR_NOTENABLED;
826         }
827         close(MidiInDev[wDevID].unixdev);
828         MidiInDev[wDevID].unixdev = 0;
829         MidiInDev[wDevID].bufsize = 0;
830         if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
831                 WARN(midi,"can't notify client !\n");
832                 return MMSYSERR_INVALPARAM;
833         }
834         return MMSYSERR_NOERROR;
835 }
836
837 /**************************************************************************
838  *                              midAddBuffer            [internal]
839  */
840 static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
841 {
842         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
843         return MMSYSERR_NOTENABLED;
844 }
845
846 /**************************************************************************
847  *                              midPrepare                      [internal]
848  */
849 static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
850 {
851         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
852         return MMSYSERR_NOTENABLED;
853 }
854
855 /**************************************************************************
856  *                              midUnprepare                    [internal]
857  */
858 static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
859 {
860         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
861         return MMSYSERR_NOTENABLED;
862 }
863
864 /**************************************************************************
865  *                      midReset                                [internal]
866  */
867 static DWORD midReset(WORD wDevID)
868 {
869         TRACE(midi, "(%04X);\n", wDevID);
870         return MMSYSERR_NOTENABLED;
871 }
872
873
874 /**************************************************************************
875  *                      midStart                                [internal]
876  */
877 static DWORD midStart(WORD wDevID)
878 {
879         TRACE(midi, "(%04X);\n", wDevID);
880         return MMSYSERR_NOTENABLED;
881 }
882
883
884 /**************************************************************************
885  *                      midStop                                 [internal]
886  */
887 static DWORD midStop(WORD wDevID)
888 {
889         TRACE(midi, "(%04X);\n", wDevID);
890         return MMSYSERR_NOTENABLED;
891 }
892
893
894 /**************************************************************************
895  *                      midMessage                              [sample driver]
896  */
897 DWORD midMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
898                                         DWORD dwParam1, DWORD dwParam2)
899 {
900         TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
901                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
902         switch(wMsg) {
903         case MIDM_OPEN:
904                 return midOpen(wDevID,(LPMIDIOPENDESC)dwParam1, dwParam2);
905         case MIDM_CLOSE:
906                 return midClose(wDevID);
907         case MIDM_ADDBUFFER:
908                 return midAddBuffer(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
909         case MIDM_PREPARE:
910                 return midPrepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
911         case MIDM_UNPREPARE:
912                 return midUnprepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
913         case MIDM_GETDEVCAPS:
914                 return midGetDevCaps(wDevID,(LPMIDIINCAPS16)dwParam1,dwParam2);
915         case MIDM_GETNUMDEVS:
916                 return 0;
917         case MIDM_RESET:
918                 return midReset(wDevID);
919         case MIDM_START:
920                 return midStart(wDevID);
921         case MIDM_STOP:
922                 return midStop(wDevID);
923         }
924         return MMSYSERR_NOTSUPPORTED;
925 }
926
927 /*-----------------------------------------------------------------------*/
928
929 /**************************************************************************
930  *                              modGetDevCaps                   [internal]
931  */
932 static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPS16 lpCaps, DWORD dwSize)
933 {
934   LPMIDIOUTCAPS16 tmplpCaps;
935
936         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
937   if (wDevID == (WORD) MIDI_MAPPER) { 
938         lpCaps->wMid = 0x00FF;  /* Manufac ID */
939         lpCaps->wPid = 0x0001;  /* Product ID */
940         lpCaps->vDriverVersion = 0x001; /* Product Version */
941     strcpy(lpCaps->szPname, "MIDI Maper (not functional yet)");
942     lpCaps->wTechnology = MOD_FMSYNTH; /* FIXME Does it make any difference ? */
943     lpCaps->wVoices     = 14;       /* FIXME */
944     lpCaps->wNotes      = 14;       /* FIXME */
945     lpCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; /* FIXME Does it make any difference ? */
946   } else {
947     /* FIXME There is a way to do it so easily, but I'm too
948      * sleepy to think and I want to test
949 */
950     tmplpCaps = midiDevices [wDevID];
951     lpCaps->wMid = tmplpCaps->wMid;  
952     lpCaps->wPid = tmplpCaps->wPid;  
953     lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;  
954     strcpy(lpCaps->szPname, tmplpCaps->szPname);    
955     lpCaps->wTechnology = tmplpCaps->wTechnology;
956     lpCaps->wVoices = tmplpCaps->wVoices;  
957     lpCaps->wNotes = tmplpCaps->wNotes;  
958     lpCaps->dwSupport = tmplpCaps->dwSupport;  
959   }
960         return MMSYSERR_NOERROR;
961 }
962
963 /**************************************************************************
964  *                      modOpen                                 [internal]
965  */
966 static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
967 {
968         int             midi;
969
970         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
971         if (lpDesc == NULL) {
972                 WARN(midi, "Invalid Parameter !\n");
973                 return MMSYSERR_INVALPARAM;
974         }
975         if (wDevID>= MAX_MIDIOUTDRV) {
976                 TRACE(midi,"MAX_MIDIOUTDRV reached !\n");
977                 return MMSYSERR_ALLOCATED; /* FIXME isn't MMSYSERR_BADDEVICEID the right answer ? */
978         }
979         MidiOutDev[wDevID].unixdev = 0;
980         midi = open (MIDI_DEV, O_WRONLY, 0);
981         if (midi == -1) {
982                 WARN(midi, "can't open !\n");
983                 return MMSYSERR_NOTENABLED;
984         }
985         MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
986         switch(MidiOutDev[wDevID].wFlags) {
987         case DCB_NULL:
988                 TRACE(midi,"CALLBACK_NULL !\n");
989                 break;
990         case DCB_WINDOW:
991                 TRACE(midi, "CALLBACK_WINDOW !\n");
992                 break;
993         case DCB_TASK:
994                 TRACE(midi, "CALLBACK_TASK !\n");
995                 break;
996         case DCB_FUNCTION:
997                 TRACE(midi, "CALLBACK_FUNCTION !\n");
998                 break;
999         }
1000         MidiOutDev[wDevID].lpQueueHdr = NULL;
1001         MidiOutDev[wDevID].unixdev = midi;
1002         MidiOutDev[wDevID].dwTotalPlayed = 0;
1003         MidiOutDev[wDevID].bufsize = 0x3FFF;
1004         if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1005                 WARN(midi,"can't notify client !\n");
1006                 return MMSYSERR_INVALPARAM;
1007         }
1008         TRACE(midi, "Succesful unixdev=%d !\n", midi);
1009         return MMSYSERR_NOERROR;
1010 }
1011
1012
1013 /**************************************************************************
1014  *                      modClose                                [internal]
1015  */
1016 static DWORD modClose(WORD wDevID)
1017 {
1018         TRACE(midi, "(%04X);\n", wDevID);
1019         if (MidiOutDev[wDevID].unixdev == 0) {
1020                 WARN(midi,"can't close !\n");
1021                 return MMSYSERR_NOTENABLED;
1022         }
1023         close(MidiOutDev[wDevID].unixdev);
1024         MidiOutDev[wDevID].unixdev = 0;
1025         MidiOutDev[wDevID].bufsize = 0;
1026         if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1027                 WARN(midi,"can't notify client !\n");
1028                 return MMSYSERR_INVALPARAM;
1029         }
1030         return MMSYSERR_NOERROR;
1031 }
1032
1033 /**************************************************************************
1034  *                      modData                                 [internal]
1035  */
1036 static DWORD modData(WORD wDevID, DWORD dwParam)
1037 {
1038         WORD    event;
1039
1040         TRACE(midi, "(%04X, %08lX);\n", wDevID, dwParam);
1041         if (MidiOutDev[wDevID].unixdev == 0) {
1042                 WARN(midi,"can't play !\n");
1043                 return MIDIERR_NODEVICE;
1044         }
1045         event = LOWORD(dwParam);
1046         if (write (MidiOutDev[wDevID].unixdev, 
1047                 &event, sizeof(WORD)) != sizeof(WORD)) {
1048                 WARN(midi, "error writting unixdev !\n");
1049         }
1050         return MMSYSERR_NOTENABLED;
1051 }
1052
1053 /**************************************************************************
1054  *              modLongData                                     [internal]
1055  */
1056 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1057 {
1058         int             count;
1059         LPWORD  ptr;
1060         int     en;
1061
1062         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1063         if (MidiOutDev[wDevID].unixdev == 0) {
1064         WARN(midi,"can't play !\n");
1065                 return MIDIERR_NODEVICE;
1066                 }
1067         if (lpMidiHdr->lpData == NULL) return MIDIERR_UNPREPARED;
1068         if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
1069         if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
1070         lpMidiHdr->dwFlags &= ~MHDR_DONE;
1071         lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1072         TRACE(midi, "dwBytesRecorded %lu !\n", lpMidiHdr->dwBytesRecorded);
1073         TRACE(midi, "                 %02X %02X %02X %02X\n",
1074                      lpMidiHdr->lpData[0], lpMidiHdr->lpData[1],
1075                      lpMidiHdr->lpData[2], lpMidiHdr->lpData[3]);
1076 /*
1077         count = write (MidiOutDev[wDevID].unixdev, 
1078                 lpMidiHdr->lpData, lpMidiHdr->dwBytesRecorded);
1079 */
1080         ptr = (LPWORD)lpMidiHdr->lpData;
1081         for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
1082                 if (write (MidiOutDev[wDevID].unixdev, ptr, 
1083                         sizeof(WORD)) != sizeof(WORD)) break;
1084                 ptr++;
1085         }
1086
1087         en = errno;
1088         TRACE(midi, "after write count = %d\n",count);
1089         if (count != lpMidiHdr->dwBytesRecorded) {
1090                 WARN(midi, "error writting unixdev #%d ! (%d != %ld)\n",
1091                              MidiOutDev[wDevID].unixdev, count, 
1092                              lpMidiHdr->dwBytesRecorded);
1093                 TRACE(midi, "\terrno = %d error = %s\n",en,strerror(en));
1094                 return MMSYSERR_NOTENABLED;
1095         }
1096         lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1097         lpMidiHdr->dwFlags |= MHDR_DONE;
1098         if (MIDI_NotifyClient(wDevID, MOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1099                 WARN(midi,"can't notify client !\n");
1100                 return MMSYSERR_INVALPARAM;
1101         }
1102         return MMSYSERR_NOERROR;
1103 }
1104
1105 /**************************************************************************
1106  *                      modPrepare                              [internal]
1107  */
1108 static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1109 {
1110         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1111         if (MidiOutDev[wDevID].unixdev == 0) {
1112                 WARN(midi,"can't prepare !\n");
1113                 return MMSYSERR_NOTENABLED;
1114         }
1115         if (MidiOutDev[wDevID].lpQueueHdr != NULL) {
1116                 TRACE(midi,"already prepare !\n");
1117                 return MMSYSERR_NOTENABLED;
1118         }
1119         MidiOutDev[wDevID].dwTotalPlayed = 0;
1120         MidiOutDev[wDevID].lpQueueHdr = PTR_SEG_TO_LIN(lpMidiHdr);
1121         if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
1122         lpMidiHdr->dwFlags |= MHDR_PREPARED;
1123         lpMidiHdr->dwFlags &= ~MHDR_DONE;
1124         return MMSYSERR_NOERROR;
1125 }
1126
1127 /**************************************************************************
1128  *                              modUnprepare                    [internal]
1129  */
1130 static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1131 {
1132         TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1133         if (MidiOutDev[wDevID].unixdev == 0) {
1134                 WARN(midi,"can't unprepare !\n");
1135                 return MMSYSERR_NOTENABLED;
1136         }
1137         return MMSYSERR_NOERROR;
1138 }
1139
1140 /**************************************************************************
1141  *                      modReset                                [internal]
1142  */
1143 static DWORD modReset(WORD wDevID)
1144 {
1145         TRACE(midi, "(%04X);\n", wDevID);
1146         return MMSYSERR_NOTENABLED;
1147 }
1148
1149
1150 /**************************************************************************
1151  *                              modMessage                      [sample driver]
1152  */
1153 DWORD modMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1154                                         DWORD dwParam1, DWORD dwParam2)
1155 {
1156         TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
1157                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1158         switch(wMsg) {
1159         case MODM_OPEN:
1160                 return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1161         case MODM_CLOSE:
1162                 return modClose(wDevID);
1163         case MODM_DATA:
1164                 return modData(wDevID, dwParam1);
1165         case MODM_LONGDATA:
1166                 return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1167         case MODM_PREPARE:
1168                 return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1169         case MODM_UNPREPARE:
1170                 return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1171         case MODM_GETDEVCAPS:
1172                 return modGetDevCaps(wDevID,(LPMIDIOUTCAPS16)dwParam1,dwParam2);
1173         case MODM_GETNUMDEVS:
1174                 return MODM_NUMDEVS;
1175         case MODM_GETVOLUME:
1176                 return 0;
1177         case MODM_SETVOLUME:
1178                 return 0;
1179         case MODM_RESET:
1180                 return modReset(wDevID);
1181         }
1182         return MMSYSERR_NOTSUPPORTED;
1183 }
1184
1185
1186 /**************************************************************************
1187  *                              MIDI_DriverProc         [sample driver]
1188  */
1189 LONG MIDI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
1190                      DWORD dwParam1, DWORD dwParam2)
1191 {
1192         switch(wMsg) {
1193         case DRV_LOAD:
1194                 return 1;
1195         case DRV_FREE:
1196                 return 1;
1197         case DRV_OPEN:
1198                 return 1;
1199         case DRV_CLOSE:
1200                 return 1;
1201         case DRV_ENABLE:
1202                 return 1;
1203         case DRV_DISABLE:
1204                 return 1;
1205         case DRV_QUERYCONFIGURE:
1206                 return 1;
1207         case DRV_CONFIGURE:
1208                 MessageBox16(0, "Sample Midi Linux Driver !", 
1209                              "MMLinux Driver", MB_OK);
1210                 return 1;
1211         case DRV_INSTALL:
1212                 return DRVCNF_RESTART;
1213         case DRV_REMOVE:
1214                 return DRVCNF_RESTART;
1215         case MCI_OPEN_DRIVER:
1216         case MCI_OPEN:
1217                 return MIDI_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1218         case MCI_CLOSE_DRIVER:
1219         case MCI_CLOSE:
1220                 return MIDI_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1221         case MCI_PLAY:
1222                 return MIDI_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1223         case MCI_RECORD:
1224                 return MIDI_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1225         case MCI_STOP:
1226                 return MIDI_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1227         case MCI_SET:
1228                 return MIDI_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1229         case MCI_PAUSE:
1230                 return MIDI_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1231         case MCI_RESUME:
1232                 return MIDI_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1233         case MCI_STATUS:
1234                 return MIDI_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1235         case MCI_GETDEVCAPS:
1236                 return MIDI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1237         case MCI_INFO:
1238                 return MIDI_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1239         default:
1240                 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1241         }
1242 }
1243 /*-----------------------------------------------------------------------*/