- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / msdos / int2f.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * DOS interrupt 2fh handler
4  *
5  *  Cdrom - device driver emulation - Audio features.
6  *      (c) 1998 Petr Tomasek <tomasek@etf.cuni.cz>
7  *      (c) 1999 Eric Pouech
8  */
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "wine/winbase16.h"
15 #include "ldt.h"
16 #include "drive.h"
17 #include "msdos.h"
18 #include "miscemu.h"
19 #include "module.h"
20 #include "task.h"
21 #include "dosexe.h"
22 #include "heap.h"
23 /* #define DEBUG_INT */
24 #include "debug.h"
25 #include "cdrom.h"
26
27 /* base WPROCS.DLL ordinal number for VxDs */
28 #define VXD_BASE 400
29
30 static void do_int2f_16( CONTEXT *context );
31 static void do_mscdex( CONTEXT *context );
32
33 /**********************************************************************
34  *          INT_Int2fHandler
35  *
36  * Handler for int 2fh (multiplex).
37  */
38 void WINAPI INT_Int2fHandler( CONTEXT *context )
39 {
40     TRACE(int,"Subfunction 0x%X\n", AX_reg(context));
41
42     switch(AH_reg(context))
43     {
44     case 0x10:
45         AL_reg(context) = 0xff; /* share is installed */
46         break;
47
48     case 0x11:  /* Network Redirector / IFSFUNC */
49         switch (AL_reg(context))
50         {
51         case 0x00:  /* Install check */
52             /* not installed */
53             break;
54         case 0x80:  /* Enhanced services - Install check */
55             /* not installed */
56             break;
57         default:
58             INT_BARF( context, 0x2f );
59             break;
60         }
61         break;
62
63     case 0x12:
64         switch (AL_reg(context))
65         {
66         case 0x2e: /* get or set DOS error table address */
67             switch (DL_reg(context))
68             {
69             /* Four tables: even commands are 'get', odd are 'set' */
70             /* DOS 5.0+ ignores "set" commands */
71             case 0x01:
72             case 0x03:
73             case 0x05:
74             case 0x07:
75             case 0x09:
76                 break; 
77             /* Instead of having a message table in DOS-space, */
78             /* we can use a special case for MS-DOS to force   */
79             /* the secondary interface.                        */
80             case 0x00:
81             case 0x02:
82             case 0x04:
83             case 0x06: 
84                 ES_reg(context) = 0x0001;
85                 DI_reg(context) = 0x0000;
86                 break;
87             case 0x08:
88                 FIXME(int, "No real-mode handler for errors yet! (bye!)");
89                 break;
90             default:
91                 INT_BARF(context, 0x2f);
92             }
93             break;
94         default:
95            INT_BARF(context, 0x2f);
96         }  
97         break;
98    
99     case 0x15: /* mscdex */
100         do_mscdex(context);
101         break;
102
103     case 0x16:
104         do_int2f_16( context );
105         break;
106
107     case 0x1a: /* ANSI.SYS / AVATAR.SYS Install Check */
108         /* Not supported yet, do nothing */
109         break;
110
111     case 0x43:
112 #if 1
113         switch (AL_reg(context))
114         {
115         case 0x00:   /* XMS v2+ installation check */
116             WARN(int,"XMS is not fully implemented\n");
117             AL_reg(context) = 0x80;
118             break;
119         case 0x10:   /* XMS v2+ get driver address */
120         {
121             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
122             NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
123             GlobalUnlock16( GetCurrentTask() );
124 #ifdef MZ_SUPPORTED
125             if (pModule && pModule->lpDosTask)
126                 ES_reg(context) = pModule->lpDosTask->xms_seg;
127             else
128 #endif
129                 ES_reg(context) = 0;
130             BX_reg(context) = 0;
131             break;
132         }
133         default:
134             INT_BARF( context, 0x2f );
135         }
136 #else
137         FIXME(int,"check for XMS (not supported)\n");
138         AL_reg(context) = 0x42; /* != 0x80 */
139 #endif
140         break;
141
142     case 0x45:
143        switch (AL_reg(context)) 
144        {
145        case 0x00:
146        case 0x01:
147        case 0x02:
148        case 0x03:
149        case 0x04:
150        case 0x05:
151        case 0x06:
152        case 0x07:
153        case 0x08:
154            /* Microsoft Profiler - not installed */
155            break;
156        default:
157             INT_BARF( context, 0x2f );
158        }
159        break;
160
161     case 0x4a:
162         switch(AL_reg(context))
163         {
164         case 0x10:  /* smartdrv */
165             break;  /* not installed */
166         case 0x11:  /* dblspace */
167             break;  /* not installed */
168         case 0x12:  /* realtime compression interface */
169             break;  /* not installed */
170         case 0x32:  /* patch IO.SYS (???) */
171             break;  /* we have no IO.SYS, so we can't patch it :-/ */
172         default:
173             INT_BARF( context, 0x2f );
174         }
175         break;
176     case 0x56:  /* INTERLNK */
177         switch(AL_reg(context))
178         {
179         case 0x01:  /* check if redirected drive */
180             AL_reg(context) = 0; /* not redirected */
181             break;
182         default:
183             INT_BARF( context, 0x2f );
184         }
185         break;
186     case 0x7a:  /* NOVELL NetWare */
187         switch (AL_reg(context))
188         {
189         case 0x20:  /* Get VLM Call Address */
190             /* return nothing -> NetWare not installed */
191             break;
192         default:
193             INT_BARF( context, 0x2f );
194             break;
195         }
196         break;
197     case 0xb7:  /* append */
198         AL_reg(context) = 0; /* not installed */
199         break;
200     case 0xb8:  /* network */
201         switch (AL_reg(context))
202         {
203         case 0x00:  /* Install check */
204             /* not installed */
205             break;
206         default:
207             INT_BARF( context, 0x2f );
208             break;
209         }
210         break;
211     case 0xbd:  /* some Novell network install check ??? */
212         AX_reg(context) = 0xa5a5; /* pretend to have Novell IPX installed */
213         break;
214     case 0xbf:  /* REDIRIFS.EXE */
215         switch (AL_reg(context))
216         {
217         case 0x00:  /* Install check */
218             /* not installed */
219             break;
220         default:
221             INT_BARF( context, 0x2f );
222             break;
223         }
224         break;
225     case 0xd7:  /* Banyan Vines */
226         switch (AL_reg(context))
227         {
228         case 0x01:  /* Install check - Get Int Number */
229             /* not installed */
230             break;
231         default:
232             INT_BARF( context, 0x2f );
233             break;
234         }
235         break;
236     case 0xfa:  /* Watcom debugger check, returns 0x666 if installed */
237         break;
238     default:
239         INT_BARF( context, 0x2f );
240         break;
241     }
242 }
243
244
245 /**********************************************************************
246  *          do_int2f_16
247  */
248 static void do_int2f_16( CONTEXT *context )
249 {
250     DWORD addr;
251
252     switch(AL_reg(context))
253     {
254     case 0x00:  /* Windows enhanced mode installation check */
255         AX_reg(context) = (GetWinFlags() & WF_ENHANCED) ?
256                                                   LOWORD(GetVersion16()) : 0;
257         break;
258         
259     case 0x0a:  /* Get Windows version and type */
260         AX_reg(context) = 0;
261         BX_reg(context) = (LOWORD(GetVersion16()) << 8) |
262                           (LOWORD(GetVersion16()) >> 8);
263         CX_reg(context) = (GetWinFlags() & WF_ENHANCED) ? 3 : 2;
264         break;
265
266     case 0x0b:  /* Identify Windows-aware TSRs */
267         /* we don't have any pre-Windows TSRs */
268         break;
269
270     case 0x11:  /* Get Shell Parameters - (SHELL= in CONFIG.SYS) */
271         /* We can mock this up. But not today... */ 
272         FIXME(int, "Get Shell Parameters\n");       
273         break;
274
275     case 0x80:  /* Release time-slice */
276         AL_reg(context) = 0;
277         break;
278
279     case 0x81: /* Begin critical section.  */
280         /* FIXME? */
281         break;
282
283     case 0x82: /* End critical section.  */
284         /* FIXME? */
285         break;
286
287     case 0x83:  /* Return Current Virtual Machine ID */
288         /* Virtual Machines are usually created/destroyed when Windows runs
289          * DOS programs. Since we never do, we are always in the System VM.
290          * According to Ralf Brown's Interrupt List, never return 0. But it
291          * seems to work okay (returning 0), just to be sure we return 1.
292          */
293         BX_reg(context) = 1; /* VM 1 is probably the System VM */
294         break;
295
296     case 0x84:  /* Get device API entry point */
297         addr = (DWORD)NE_GetEntryPoint( GetModuleHandle16("WPROCS"),
298                                         VXD_BASE + BX_reg(context) );
299         if (!addr)  /* not supported */
300         {
301             ERR(int,"Accessing unknown VxD %04x - Expect a failure now.\n",
302                      BX_reg(context) );
303         }
304         ES_reg(context) = SELECTOROF(addr);
305         DI_reg(context) = OFFSETOF(addr);
306         break;
307
308     case 0x86:  /* DPMI detect mode */
309         AX_reg(context) = 0;  /* Running under DPMI */
310         break;
311
312     case 0x87: /* DPMI installation check */
313 #if 1   /* DPMI still breaks pkunzip */
314         if (ISV86(context)) break; /* so bail out for now if in v86 mode */
315 #endif
316         {
317             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
318             NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
319             SYSTEM_INFO si;
320
321             GlobalUnlock16( GetCurrentTask() );
322             GetSystemInfo(&si);
323             AX_reg(context) = 0x0000; /* DPMI Installed */
324             BX_reg(context) = 0x0001; /* 32bits available */
325             CL_reg(context) = si.wProcessorLevel;
326             DX_reg(context) = 0x005a; /* DPMI major/minor 0.90 */
327             SI_reg(context) = 0;      /* # of para. of DOS extended private data */
328 #ifdef MZ_SUPPORTED                   /* ES:DI is DPMI switch entry point */
329             if (pModule && pModule->lpDosTask)
330                 ES_reg(context) = pModule->lpDosTask->dpmi_seg;
331             else
332 #endif
333                 ES_reg(context) = 0;
334             DI_reg(context) = 0;
335             break;
336         }
337     case 0x8a:  /* DPMI get vendor-specific API entry point. */
338         /* The 1.0 specs say this should work with all 0.9 hosts.  */
339         break;
340
341     default:
342         INT_BARF( context, 0x2f );
343     }
344 }
345
346 void do_mscdex( CONTEXT *context )
347 {
348     int         drive, count;
349     char*       p;
350
351     switch(AL_reg(context)) {
352     case 0x00: /* Installation check */
353         /* Count the number of contiguous CDROM drives
354          */
355         for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++) {
356             if (DRIVE_GetType(drive) == TYPE_CDROM) {
357                 while (DRIVE_GetType(drive + count) == TYPE_CDROM) count++;
358                 break;
359             }
360         }
361         TRACE(int, "Installation check: %d cdroms, starting at %d\n", count, drive);
362         BX_reg(context) = count;
363         CX_reg(context) = (drive < MAX_DOS_DRIVES) ? drive : 0;
364         break;
365         
366     case 0x0B: /* drive check */
367         AX_reg(context) = (DRIVE_GetType(CX_reg(context)) == TYPE_CDROM);
368         BX_reg(context) = 0xADAD;
369         break;
370         
371     case 0x0C: /* get version */
372         BX_reg(context) = 0x020a;
373         break;
374         
375     case 0x0D: /* get drive letters */
376         p = CTX_SEG_OFF_TO_LIN(context, ES_reg(context), EBX_reg(context));
377         memset( p, 0, MAX_DOS_DRIVES );
378         for (drive = 0; drive < MAX_DOS_DRIVES; drive++) {
379             if (DRIVE_GetType(drive) == TYPE_CDROM) *p++ = drive;
380         }
381         break;
382         
383     case 0x10: /* direct driver acces */
384     {
385         static  WINE_CDAUDIO    wcda;
386         BYTE*   driver_request;
387         BYTE*   io_stru;        
388         u_char  Error = 255; /* No Error */ 
389         int     dorealmode = ISV86(context);
390         
391         driver_request = (dorealmode) ? 
392             DOSMEM_MapRealToLinear(MAKELONG(BX_reg(context),ES_reg(context))) : 
393             PTR_SEG_OFF_TO_LIN(ES_reg(context),BX_reg(context));
394         
395         if (!driver_request) {
396             /* FIXME - to be deleted ?? */
397             ERR(int,"   ES:BX==0 ! SEGFAULT ?\n");
398             ERR(int," -->BX=0x%04x, ES=0x%04lx, DS=0x%04lx, CX=0x%04x\n",
399                 BX_reg(context), ES_reg(context), DS_reg(context), CX_reg(context));
400         } else {
401             /* FIXME - would be best to open the device at the begining of the wine session .... 
402              */
403             if (wcda.unixdev <= 0) 
404                 CDAUDIO_Open(&wcda);
405         }
406         TRACE(int,"CDROM device driver -> command <%d>\n", (unsigned char)driver_request[2]);
407         
408         /* set status to 0 */
409         driver_request[3] = driver_request[4] = 0;
410         CDAUDIO_GetCDStatus(&wcda);
411         
412         switch (driver_request[2]) {
413         case 3:
414             io_stru = (dorealmode) ? 
415                 DOSMEM_MapRealToLinear(MAKELONG(*((WORD*)(driver_request + 14)), *((WORD*)(driver_request + 16)))) :
416                     PTR_SEG_OFF_TO_LIN(*((WORD*)(driver_request + 16)), *((WORD*)(driver_request + 18)));
417             
418             TRACE(int," --> IOCTL INPUT <%d>\n", io_stru[0]); 
419             switch (io_stru[0]) {
420 #if 0
421             case 0: /* Get device Header */
422             {
423                 static  LPSTR ptr = 0;
424                 if (ptr == 0)   {
425                     ptr = SEGPTR_ALLOC(22);
426                     *((DWORD*)(ptr     )) = ~1;         /* Next Device Driver */
427                     *((WORD* )(ptr +  4)) = 0xC800;     /* Device attributes  */
428                     *((WORD* )(ptr +  6)) = 0x1234;     /* Pointer to device strategy routine: FIXME */
429                     *((WORD* )(ptr +  8)) = 0x3142;     /* Pointer to device interrupt routine: FIXME */
430                     *((char*) (ptr + 10)) = 'W';        /* 8-byte character device name field */
431                     *((char*) (ptr + 11)) = 'I';
432                     *((char*) (ptr + 12)) = 'N';
433                     *((char*) (ptr + 13)) = 'E';
434                     *((char*) (ptr + 14)) = '_';
435                     *((char*) (ptr + 15)) = 'C';
436                     *((char*) (ptr + 16)) = 'D';
437                     *((char*) (ptr + 17)) = '_';
438                     *((WORD*) (ptr + 18)) = 0;          /* Reserved (must be zero) */
439                     *((BYTE*) (ptr + 20)) = 0;          /* Drive letter (must be zero) */
440                     *((BYTE*) (ptr + 21)) = 1;          /* Number of units supported (one or more) FIXME*/
441                 }
442                 ((DWORD*)io_stru+1)[0] = SEGPTR_GET(ptr);
443             }
444             break;
445 #endif
446             
447             case 1: /* location of head */
448                 if (io_stru[1] == 0) {
449                     /* FIXME: what if io_stru+2 is not DWORD aligned ? */
450                     ((DWORD*)io_stru+2)[0] = wcda.dwCurFrame;
451                     TRACE(int," ----> HEAD LOCATION <%ld>\n", ((DWORD*)io_stru+2)[0]); 
452                 } else {
453                     ERR(int,"CDRom-Driver: Unsupported addressing mode !!\n");
454                     Error = 0x0c;
455                 }
456                 break;
457                 
458             case 4: /* Audio channel info */
459                 io_stru[1] = 0;
460                 io_stru[2] = 0xff;
461                 io_stru[3] = 1;
462                 io_stru[4] = 0xff;
463                 io_stru[5] = 2;
464                 io_stru[6] = 0xff;
465                 io_stru[7] = 3;
466                 io_stru[8] = 0xff;
467                 TRACE(int," ----> AUDIO CHANNEL CONTROL\n"); 
468                 break;
469                 
470             case 6: /* device status */
471                 /* FIXME .. does this work properly ?? */
472                 io_stru[3] = io_stru[4] = 0;
473                 io_stru[2] = 1;  /* supports audio channels (?? FIXME ??) */
474                 io_stru[1] = 16; /* data read and plays audio tracks */
475                 if (wcda.cdaMode == WINE_CDA_OPEN)
476                     io_stru[1] |= 1;
477                 TRACE(int," ----> DEVICE STATUS <0x%08lx>\n", (DWORD)io_stru[1]); 
478                 break;
479                 
480             case 8: /* Volume size */
481                 *((DWORD*)(io_stru+1)) = wcda.dwTotalLen;
482                 TRACE(int," ----> VOLMUE SIZE <0x%08lx>\n", *((DWORD*)(io_stru+1))); 
483                 break;
484                 
485             case 9: /* media changed ? */
486                 /* answers don't know... -1/1 for yes/no would be better */
487                 io_stru[0] = 0; /* FIXME? 1? */
488                 break;
489                 
490             case 10: /* audio disk info */
491                 io_stru[1] = wcda.nFirstTrack; /* starting track of the disc */
492                 io_stru[2] = wcda.nLastTrack; /* ending track */
493                 ((DWORD*)io_stru+3)[0] = wcda.dwFirstOffset;
494                 TRACE(int," ----> AUDIO DISK INFO <%d-%d/%ld>\n",
495                       io_stru[1], io_stru[2], ((DWORD *)io_stru+3)[0]); 
496                 break;
497                 
498             case 11: /* audio track info */
499                 ((DWORD*)io_stru+2)[0] = wcda.lpdwTrackPos[io_stru[1]];
500                 /* starting point if the track */
501                 io_stru[6] = wcda.lpbTrackFlags[io_stru[1]];
502                 TRACE(int," ----> AUDIO TRACK INFO <track=%d>[%ld:%d]\n",
503                       io_stru[1],((DWORD *)io_stru+2)[0], io_stru[6]); 
504                 break;
505                 
506             case 12: /* get Q-Channel / Subchannel (??) info */
507                 io_stru[ 1] = wcda.lpbTrackFlags[wcda.nCurTrack];
508                 io_stru[ 2] = wcda.nCurTrack;
509                 io_stru[ 3] = 0; /* FIXME ?? */
510                 {
511                     DWORD  f = wcda.lpdwTrackPos[wcda.nCurTrack] - wcda.dwCurFrame;
512                     io_stru[ 4] = f / CDFRAMES_PERMIN;
513                     io_stru[ 5] = (f - CDFRAMES_PERMIN * io_stru[4]) / CDFRAMES_PERSEC;
514                     io_stru[ 6] = f - CDFRAMES_PERMIN * io_stru[4] - CDFRAMES_PERSEC * io_stru[5];
515                 }
516                 io_stru[ 7] = 0;
517                 {
518                     DWORD  f = wcda.dwCurFrame;
519                     io_stru[ 8] = f / CDFRAMES_PERMIN;
520                     io_stru[ 9] = (f - CDFRAMES_PERMIN * io_stru[4]) / CDFRAMES_PERSEC;
521                     io_stru[10] = f - CDFRAMES_PERMIN * io_stru[4] - CDFRAMES_PERSEC * io_stru[5];
522                 }
523                 break;
524                 
525             case 15: /* Audio status info */
526                 /* !!!! FIXME FIXME FIXME !! */
527                 *((WORD*)(io_stru+1))  = (wcda.cdaMode == WINE_CDA_PAUSE);
528                 *((DWORD*)(io_stru+3)) = wcda.lpdwTrackPos[0];
529                 *((DWORD*)(io_stru+7)) = wcda.lpdwTrackPos[wcda.nTracks - 1];
530                 break;
531                 
532             default:
533                 FIXME(int," Cdrom-driver: IOCTL INPUT: Unimplemented <%d>!!\n", io_stru[0]); 
534                 Error=0x0c; 
535                 break;  
536             }   
537             break;
538             
539         case 12:
540             io_stru = (dorealmode) ? 
541                 DOSMEM_MapRealToLinear(MAKELONG(*((WORD*)(driver_request + 14)), *((WORD*)(driver_request + 16)))) :
542                     PTR_SEG_OFF_TO_LIN(*((WORD*)(driver_request + 16)), *((WORD*)(driver_request + 18)));
543             
544             TRACE(int," --> IOCTL OUTPUT <%d>\n",io_stru[0]); 
545             switch (io_stru[0]) {
546             case 0: /* eject */ 
547                 CDAUDIO_SetDoor(&wcda, 1);
548                 TRACE(int," ----> EJECT\n"); 
549                 break;
550             case 2: /* reset drive */
551                 CDAUDIO_Reset(&wcda);
552                 TRACE(int," ----> RESET\n"); 
553                 break;
554             case 3: /* Audio Channel Control */
555                 FIXME(int, " ----> AUDIO CHANNEL CONTROL (NIY)\n");
556                 break;
557             case 5: /* close tray */
558                 CDAUDIO_SetDoor(&wcda, 0);
559                 TRACE(int," ----> CLOSE TRAY\n"); 
560                 break;
561             default:
562                 FIXME(int," Cdrom-driver: IOCTL OUPUT: Unimplemented <%d>!!\n",
563                       io_stru[0]); 
564                 Error=0x0c;
565                 break;  
566             }   
567             break;
568             
569         case 132:  /* FIXME - It didn't function for me... */
570             TRACE(int," --> PLAY AUDIO\n");
571             if (driver_request[13] == 0) {
572                 TRACE(int,"Mode :<0x%02X> , [%ld-%ld]\n",
573                       (unsigned char)driver_request[13],
574                       ((DWORD*)driver_request+14)[0],
575                       ((DWORD*)driver_request+18)[0]);
576                 CDAUDIO_Play(&wcda, ((DWORD*)driver_request+14)[0], ((DWORD*)driver_request+14)[0] + ((DWORD*)driver_request+18)[0]);
577             } else {
578                 ERR(int, "CDRom-Driver: Unsupported address mode !!\n");
579                 Error=0x0c;
580             }
581             break;
582             
583         case 133:
584             if (wcda.cdaMode == WINE_CDA_PLAY) {
585                 CDAUDIO_Pause(&wcda, 1);
586                 TRACE(int," --> STOP AUDIO (Paused)\n");
587             } else {
588                 CDAUDIO_Stop(&wcda);
589                 TRACE(int," --> STOP AUDIO (Stopped)\n");
590             }
591             break;
592             
593         case 136:
594             TRACE(int," --> RESUME AUDIO\n");
595             CDAUDIO_Pause(&wcda, 0);
596             break;
597             
598         default:
599             FIXME(int," CDRom-Driver - ioctl uninplemented <%d>\n",driver_request[2]); 
600             Error=0x0c; 
601         }
602         
603         if (Error<255) {
604             driver_request[4] |= 127;
605             driver_request[3] = Error;
606         }
607         driver_request[4] |= 2 * (wcda.cdaMode = WINE_CDA_PLAY);
608         
609         /*  close (fdcd); FIXME !! -- cannot use close when ejecting 
610             the cd-rom - close would close it again */ 
611     }
612     break;
613     default:
614         FIXME(int, "Unimplemented MSCDEX function 0x%02X.\n", AL_reg(context));
615         break;
616     }
617 }