If using the default values, also set dwType to REG_SZ as our default
[wine] / dlls / winedos / int13.c
1 /*
2  * BIOS interrupt 13h handler
3  *
4  * Copyright 1997 Andreas Mohr
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_IOCTL_H
30 # include <sys/ioctl.h>
31 #endif
32 #include <fcntl.h>
33 #ifdef linux
34 # include <linux/fd.h>
35 #endif
36
37 #include "dosexe.h"
38 #include "wine/debug.h"
39 #include "drive.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(int);
42
43
44 /*
45  * Status of last int13 operation.
46  */
47 static BYTE INT13_last_status;
48
49
50 /**********************************************************************
51  *         INT13_SetStatus
52  *
53  * Write status to AH register and set carry flag on error (AH != 0).
54  *
55  * Despite what Ralf Brown says, at least functions 0x06 and 0x07 
56  * seem to set carry, too.
57  */
58 static void INT13_SetStatus( CONTEXT86 *context, BYTE status )
59 {
60     INT13_last_status = status;
61
62     SET_AH( context, status );
63
64     if (status)
65         SET_CFLAG( context );
66     else
67         RESET_CFLAG( context );        
68 }
69
70
71 /**********************************************************************
72  *          INT13_ReadFloppyParams
73  *
74  * Read floppy disk parameters.
75  */
76 static void INT13_ReadFloppyParams( CONTEXT86 *context )
77 {
78 #ifdef linux
79     static const BYTE floppy_params[2][13] =
80     {
81         { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 },
82         { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 }
83     };
84
85     static const DWORD drive_type_info[7]={
86         0x0000, /* none */
87         0x2709, /* 360 K */
88         0x4f0f, /* 1.2 M */
89         0x4f09, /* 720 K */
90         0x4f12, /* 1.44 M */
91         0x4f24, /* 2.88 M */
92         0x4f24  /* 2.88 M */
93     };
94
95     unsigned int i;
96     unsigned int nr_of_drives = 0;
97     BYTE drive_nr = DL_reg( context );
98     int floppy_fd;
99     int r;
100     struct floppy_drive_params floppy_parm;
101     char root[] = "A:\\";
102
103     TRACE("in  [ EDX=%08lx ]\n", context->Edx );
104
105     SET_AL( context, 0 );
106     SET_BX( context, 0 );
107     SET_CX( context, 0 );
108     SET_DH( context, 0 );
109
110     for (i = 0; i < MAX_DOS_DRIVES; i++, root[0]++)
111         if (GetDriveTypeA(root) == DRIVE_REMOVABLE) nr_of_drives++;
112     SET_DL( context, nr_of_drives );
113
114     if (drive_nr > 1) { 
115         /* invalid drive ? */
116         INT13_SetStatus( context, 0x07 ); /* drive parameter activity failed */
117         return;
118     }
119
120     if ( (floppy_fd = DRIVE_OpenDevice( drive_nr, O_RDONLY|O_NONBLOCK)) == -1)
121     {
122         WARN("Can't determine floppy geometry !\n");
123         INT13_SetStatus( context, 0x07 ); /* drive parameter activity failed */
124         return;
125     }
126     r = ioctl(floppy_fd, FDGETDRVPRM, &floppy_parm);
127  
128     close(floppy_fd);
129
130     if(r<0)
131     {
132         INT13_SetStatus( context, 0x07 ); /* drive parameter activity failed */
133         return;
134     }
135
136     SET_BL( context, floppy_parm.cmos );
137
138     /*
139      * CH = low eight bits of max cyl
140      * CL = max sec nr (bits 5-0),
141      *      hi two bits of max cyl (bits 7-6)
142      * DH = max head nr 
143      */
144     if(BL_reg( context ) && BL_reg( context ) < 7)
145     {
146         SET_DH( context, 0x01 );
147         SET_CX( context, drive_type_info[BL_reg( context )] );
148     }
149
150     context->Edi = (DWORD)floppy_params[drive_nr];
151
152     if(!context->Edi)
153     {
154         ERR("Get floppy params failed for drive %d\n", drive_nr);
155         INT13_SetStatus( context, 0x07 ); /* drive parameter activity failed */
156         return;
157     }
158
159     TRACE("out [ EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx EDI=%08lx ]\n",
160           context->Eax, context->Ebx, context->Ecx, context->Edx, context->Edi);
161
162     INT13_SetStatus( context, 0x00 ); /* success */
163
164     /* FIXME: Word exits quietly if we return with no error. Why? */
165     FIXME("Returned ERROR!\n");
166     SET_CFLAG( context );
167
168 #else
169     INT13_SetStatus( context, 0x01 ); /* invalid function */
170 #endif
171 }
172
173
174 /**********************************************************************
175  *         DOSVM_Int13Handler (WINEDOS16.119)
176  *
177  * Handler for int 13h (disk I/O).
178  */
179 void WINAPI DOSVM_Int13Handler( CONTEXT86 *context )
180 {
181     TRACE( "AH=%02x\n", AH_reg( context ) );
182
183     switch( AH_reg( context ) )
184     {
185     case 0x00: /* RESET DISK SYSTEM */
186         INT13_SetStatus( context, 0x00 ); /* success */
187         break;
188
189     case 0x01: /* STATUS OF DISK SYSTEM */
190         INT13_SetStatus( context, INT13_last_status );
191         break;
192
193     case 0x02: /* READ SECTORS INTO MEMORY */
194         SET_AL( context, 0 ); /* number of sectors transferred */
195         INT13_SetStatus( context, 0x00 ); /* success */
196         break;
197
198     case 0x03: /* WRITE SECTORS FROM MEMORY */
199         SET_AL( context, 0 ); /* number of sectors transferred */
200         INT13_SetStatus( context, 0x00 ); /* success */
201         break;
202
203     case 0x04: /* VERIFY DISK SECTOR(S) */
204         SET_AL( context, 0 ); /* number of sectors verified */
205         INT13_SetStatus( context, 0x00 ); /* success */
206         break;
207
208     case 0x05: /* FORMAT TRACK */
209     case 0x06: /* FORMAT TRACK AND SET BAD SECTOR FLAGS */
210     case 0x07: /* FORMAT DRIVE STARTING AT GIVEN TRACK  */
211         INT13_SetStatus( context, 0x0c ); /* unsupported track or invalid media */
212         break;
213
214     case 0x08: /* GET DRIVE PARAMETERS  */
215         if (DL_reg( context ) & 0x80) 
216         {
217             /* hard disk ? */
218             INT13_SetStatus( context, 0x07 ); /* drive parameter activity failed */
219         }
220         else
221         { 
222             /* floppy disk */
223             INT13_ReadFloppyParams( context );
224         }
225         break;
226
227     case 0x09: /* INITIALIZE CONTROLLER WITH DRIVE PARAMETERS */
228     case 0x0a: /* FIXED DISK - READ LONG */
229     case 0x0b: /* FIXED DISK - WRITE LONG */
230     case 0x0c: /* SEEK TO CYLINDER */
231     case 0x0d: /* ALTERNATE RESET HARD DISK */
232         INT13_SetStatus( context, 0x00 ); /* success */
233         break;
234
235     case 0x0e: /* READ SECTOR BUFFER */
236     case 0x0f: /* WRITE SECTOR BUFFER */
237         INT13_SetStatus( context, 0x01 ); /* invalid function */
238         break;
239
240     case 0x10: /* CHECK IF DRIVE READY */
241     case 0x11: /* RECALIBRATE DRIVE */
242         INT13_SetStatus( context, 0x00 ); /* success */
243         break;
244
245     case 0x12: /* CONTROLLER RAM DIAGNOSTIC */
246     case 0x13: /* DRIVE DIAGNOSTIC */
247         INT13_SetStatus( context, 0x01 ); /* invalid function */
248         break;
249
250     case 0x14: /* CONTROLLER INTERNAL DIAGNOSTIC */
251         INT13_SetStatus( context, 0x00 ); /* success */
252         break;
253
254     case 0x15: /* GET DISK TYPE */
255         if (DL_reg( context ) & 0x80) 
256         {
257             /* hard disk ? */
258             INT13_SetStatus( context, 0x00 ); /* success */
259             /* type is fixed disk, overwrites status */
260             SET_AH( context, 0x03 );
261         }
262         else
263         { 
264             /* floppy disk */
265             INT13_SetStatus( context, 0x00 ); /* success */
266             /* type is floppy with change detection, overwrites status */
267             SET_AH( context, 0x02 );
268         }
269         break;
270
271     case 0x16: /* FLOPPY - CHANGE OF DISK STATUS */
272         INT13_SetStatus( context, 0x00 ); /* success */
273         break;
274
275     case 0x17: /* SET DISK TYPE FOR FORMAT */
276         if (DL_reg( context ) < 4)
277             INT13_SetStatus( context, 0x00 ); /* successful completion */
278         else
279             INT13_SetStatus( context, 0x01 ); /* error */
280         break;
281
282     case 0x18: /* SET MEDIA TYPE FOR FORMAT */
283         if (DL_reg( context ) < 4)
284             INT13_SetStatus( context, 0x00 ); /* success */
285         else
286             INT13_SetStatus( context, 0x01 ); /* error */
287         break;
288
289     case 0x19: /* FIXED DISK - PARK HEADS */
290         INT13_SetStatus( context, 0x00 ); /* success */
291         break;
292
293     default:
294         INT_BARF( context, 0x13 );
295         INT13_SetStatus( context, 0x01 ); /* invalid function */
296     } 
297 }