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