Better mmap failure error message.
[wine/multimedia.git] / dlls / winedos / devices.c
blobd5f193ee048492f429e70c93d6e19437b67488f5
1 /*
2 * DOS devices
4 * Copyright 1999 Ove Kåven
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.
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.
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
21 #include <stdlib.h>
22 #include <string.h>
23 #include "wine/winbase16.h"
24 #include "dosexe.h"
25 #include "wine/debug.h"
27 #include "pshpack1.h"
29 typedef struct {
30 BYTE ljmp1;
31 RMCBPROC strategy;
32 BYTE ljmp2;
33 RMCBPROC interrupt;
34 } WINEDEV_THUNK;
36 typedef struct {
37 BYTE size; /* length of header + data */
38 BYTE unit; /* unit (block devices only) */
39 BYTE command;
40 WORD status;
41 BYTE reserved[8];
42 } REQUEST_HEADER;
44 typedef struct {
45 REQUEST_HEADER hdr;
46 BYTE media; /* media descriptor from BPB */
47 SEGPTR buffer;
48 WORD count; /* byte/sector count */
49 WORD sector; /* starting sector (block devices) */
50 DWORD volume; /* volume ID (block devices) */
51 } REQ_IO;
53 typedef struct {
54 REQUEST_HEADER hdr;
55 BYTE data;
56 } REQ_SAFEINPUT;
58 typedef struct
60 DWORD next_dev;
61 WORD attr;
62 WORD strategy;
63 WORD interrupt;
64 char name[8];
65 } DOS_DEVICE_HEADER;
67 /* Warning: need to return LOL ptr w/ offset 0 (&ptr_first_DPB) to programs ! */
68 typedef struct _DOS_LISTOFLISTS
70 WORD CX_Int21_5e01; /* -24d contents of CX from INT 21/AX=5E01h */
71 WORD LRU_count_FCB_cache; /* -22d */
72 WORD LRU_count_FCB_open; /* -20d */
73 DWORD OEM_func_handler; /* -18d OEM function of INT 21/AH=F8h */
74 WORD INT21_offset; /* -14d offset in DOS CS of code to return from INT 21 call */
75 WORD sharing_retry_count; /* -12d */
76 WORD sharing_retry_delay; /* -10d */
77 DWORD ptr_disk_buf; /* -8d ptr to current disk buf */
78 WORD offs_unread_CON; /* -4d pointer in DOS data segment of unread CON input */
79 WORD seg_first_MCB; /* -2d */
80 DWORD ptr_first_DPB; /* 00 */
81 DWORD ptr_first_SysFileTable; /* 04 */
82 DWORD ptr_clock_dev_hdr; /* 08 */
83 DWORD ptr_CON_dev_hdr; /* 0C */
84 WORD max_byte_per_sec; /* 10 maximum bytes per sector of any block device */
85 DWORD ptr_disk_buf_info; /* 12 */
86 DWORD ptr_array_CDS; /* 16 current directory structure */
87 DWORD ptr_sys_FCB; /* 1A */
88 WORD nr_protect_FCB; /* 1E */
89 BYTE nr_block_dev; /* 20 */
90 BYTE nr_avail_drive_letters; /* 21 */
91 DOS_DEVICE_HEADER NUL_dev; /* 22 */
92 BYTE nr_drives_JOINed; /* 34 */
93 WORD ptr_spec_prg_names; /* 35 */
94 DWORD ptr_SETVER_prg_list; /* 37 */
95 WORD DOS_HIGH_A20_func_offs;/* 3B */
96 WORD PSP_last_exec; /* 3D if DOS in HMA: PSP of program executed last; if DOS low: 0000h */
97 WORD BUFFERS_val; /* 3F */
98 WORD BUFFERS_nr_lookahead; /* 41 */
99 BYTE boot_drive; /* 43 */
100 BYTE flag_DWORD_moves; /* 44 01h for 386+, 00h otherwise */
101 WORD size_extended_mem; /* 45 size of extended mem in KB */
102 SEGPTR wine_rm_lol; /* -- wine: Real mode pointer to LOL */
103 SEGPTR wine_pm_lol; /* -- wine: Protected mode pointer to LOL */
104 } DOS_LISTOFLISTS;
106 #include "poppack.h"
108 #define CON_BUFFER 128
110 enum strategy { SYSTEM_STRATEGY_NUL, SYSTEM_STRATEGY_CON, NB_SYSTEM_STRATEGIES };
112 static void *strategy_data[NB_SYSTEM_STRATEGIES];
114 #define NONEXT ((DWORD)-1)
116 #define ATTR_STDIN 0x0001
117 #define ATTR_STDOUT 0x0002
118 #define ATTR_NUL 0x0004
119 #define ATTR_CLOCK 0x0008
120 #define ATTR_FASTCON 0x0010
121 #define ATTR_RAW 0x0020
122 #define ATTR_NOTEOF 0x0040
123 #define ATTR_DEVICE 0x0080
124 #define ATTR_REMOVABLE 0x0800
125 #define ATTR_NONIBM 0x2000 /* block devices */
126 #define ATTR_UNTILBUSY 0x2000 /* char devices */
127 #define ATTR_IOCTL 0x4000
128 #define ATTR_CHAR 0x8000
130 #define CMD_INIT 0
131 #define CMD_MEDIACHECK 1 /* block devices */
132 #define CMD_BUILDBPB 2 /* block devices */
133 #define CMD_INIOCTL 3
134 #define CMD_INPUT 4 /* read data */
135 #define CMD_SAFEINPUT 5 /* "non-destructive input no wait", char devices */
136 #define CMD_INSTATUS 6 /* char devices */
137 #define CMD_INFLUSH 7 /* char devices */
138 #define CMD_OUTPUT 8 /* write data */
139 #define CMD_SAFEOUTPUT 9 /* write data with verify */
140 #define CMD_OUTSTATUS 10 /* char devices */
141 #define CMD_OUTFLUSH 11 /* char devices */
142 #define CMD_OUTIOCTL 12
143 #define CMD_DEVOPEN 13
144 #define CMD_DEVCLOSE 14
145 #define CMD_REMOVABLE 15 /* block devices */
146 #define CMD_UNTILBUSY 16 /* output until busy */
148 #define STAT_MASK 0x00FF
149 #define STAT_DONE 0x0100
150 #define STAT_BUSY 0x0200
151 #define STAT_ERROR 0x8000
153 #define LJMP 0xea
156 /* prototypes */
157 static void WINAPI nul_strategy(CONTEXT86*ctx);
158 static void WINAPI nul_interrupt(CONTEXT86*ctx);
159 static void WINAPI con_strategy(CONTEXT86*ctx);
160 static void WINAPI con_interrupt(CONTEXT86*ctx);
162 /* devices */
163 typedef struct
165 char name[8];
166 WORD attr;
167 RMCBPROC strategy;
168 RMCBPROC interrupt;
169 } WINEDEV;
171 static WINEDEV devs[] =
173 { "NUL ",
174 ATTR_CHAR|ATTR_NUL|ATTR_DEVICE,
175 nul_strategy, nul_interrupt },
177 { "CON ",
178 ATTR_CHAR|ATTR_STDIN|ATTR_STDOUT|ATTR_FASTCON|ATTR_NOTEOF|ATTR_DEVICE,
179 con_strategy, con_interrupt }
182 #define NR_DEVS (sizeof(devs)/sizeof(WINEDEV))
184 /* DOS data segment */
185 typedef struct
187 DOS_LISTOFLISTS lol;
188 DOS_DEVICE_HEADER dev[NR_DEVS-1];
189 WINEDEV_THUNK thunk[NR_DEVS];
190 REQ_IO req;
191 BYTE buffer[CON_BUFFER];
193 } DOS_DATASEG;
195 #define DOS_DATASEG_OFF(xxx) FIELD_OFFSET(DOS_DATASEG, xxx)
197 DWORD DOS_LOLSeg;
199 static struct _DOS_LISTOFLISTS * DOSMEM_LOL()
201 return PTR_REAL_TO_LIN(HIWORD(DOS_LOLSeg),0);
205 /* the device implementations */
206 static void do_lret(CONTEXT86*ctx)
208 WORD *stack = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegSs, ctx->Esp);
210 ctx->Eip = *(stack++);
211 ctx->SegCs = *(stack++);
212 ctx->Esp += 2*sizeof(WORD);
215 static void do_strategy(CONTEXT86*ctx, int id, int extra)
217 REQUEST_HEADER *hdr = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegEs, ctx->Ebx);
218 void **hdr_ptr = strategy_data[id];
220 if (!hdr_ptr) {
221 hdr_ptr = calloc(1,sizeof(void *)+extra);
222 strategy_data[id] = hdr_ptr;
224 *hdr_ptr = hdr;
225 do_lret(ctx);
228 static REQUEST_HEADER * get_hdr(int id, void**extra)
230 void **hdr_ptr = strategy_data[id];
231 if (extra)
232 *extra = hdr_ptr ? (void*)(hdr_ptr+1) : (void *)NULL;
233 return hdr_ptr ? *hdr_ptr : (void *)NULL;
236 static void WINAPI nul_strategy(CONTEXT86*ctx)
238 do_strategy(ctx, SYSTEM_STRATEGY_NUL, 0);
241 static void WINAPI nul_interrupt(CONTEXT86*ctx)
243 REQUEST_HEADER *hdr = get_hdr(SYSTEM_STRATEGY_NUL, NULL);
244 /* eat everything and recycle nothing */
245 switch (hdr->command) {
246 case CMD_INPUT:
247 ((REQ_IO*)hdr)->count = 0;
248 hdr->status = STAT_DONE;
249 break;
250 case CMD_SAFEINPUT:
251 hdr->status = STAT_DONE|STAT_BUSY;
252 break;
253 default:
254 hdr->status = STAT_DONE;
256 do_lret(ctx);
259 static void WINAPI con_strategy(CONTEXT86*ctx)
261 do_strategy(ctx, SYSTEM_STRATEGY_CON, sizeof(int));
264 static void WINAPI con_interrupt(CONTEXT86*ctx)
266 int *scan;
267 REQUEST_HEADER *hdr = get_hdr(SYSTEM_STRATEGY_CON,(void **)&scan);
268 BIOSDATA *bios = DOSVM_BiosData();
269 WORD CurOfs = bios->NextKbdCharPtr;
270 DOS_LISTOFLISTS *lol = DOSMEM_LOL();
271 DOS_DATASEG *dataseg = (DOS_DATASEG *)lol;
272 BYTE *linebuffer = dataseg->buffer;
273 BYTE *curbuffer = (lol->offs_unread_CON) ?
274 (((BYTE*)dataseg) + lol->offs_unread_CON) : (BYTE*)NULL;
275 DOS_DEVICE_HEADER *con = dataseg->dev;
277 switch (hdr->command) {
278 case CMD_INPUT:
280 REQ_IO *io = (REQ_IO *)hdr;
281 WORD count = io->count, len = 0;
282 BYTE *buffer = CTX_SEG_OFF_TO_LIN(ctx,
283 SELECTOROF(io->buffer),
284 (DWORD)OFFSETOF(io->buffer));
286 hdr->status = STAT_BUSY;
287 /* first, check whether we already have data in line buffer */
288 if (curbuffer) {
289 /* yep, copy as much as we can */
290 BYTE data = 0;
291 while ((len<count) && (data != '\r')) {
292 data = *curbuffer++;
293 buffer[len++] = data;
295 if (data == '\r') {
296 /* line buffer emptied */
297 lol->offs_unread_CON = 0;
298 curbuffer = NULL;
299 /* if we're not in raw mode, call it a day */
300 if (!(con->attr & ATTR_RAW)) {
301 hdr->status = STAT_DONE;
302 io->count = len;
303 break;
305 } else {
306 /* still some data left */
307 lol->offs_unread_CON = curbuffer - (BYTE*)lol;
308 /* but buffer was filled, we're done */
309 hdr->status = STAT_DONE;
310 io->count = len;
311 break;
315 /* if we're in raw mode, we just need to fill the buffer */
316 if (con->attr & ATTR_RAW) {
317 while (len<count) {
318 WORD data;
320 /* do we have a waiting scancode? */
321 if (*scan) {
322 /* yes, store scancode in buffer */
323 buffer[len++] = *scan;
324 *scan = 0;
325 if (len==count) break;
328 /* check for new keyboard input */
329 while (CurOfs == bios->FirstKbdCharPtr) {
330 /* no input available yet, so wait... */
331 DOSVM_Wait( ctx );
333 /* read from keyboard queue (call int16?) */
334 data = ((WORD*)bios)[CurOfs];
335 CurOfs += 2;
336 if (CurOfs >= bios->KbdBufferEnd) CurOfs = bios->KbdBufferStart;
337 bios->NextKbdCharPtr = CurOfs;
338 /* if it's an extended key, save scancode */
339 if (LOBYTE(data) == 0) *scan = HIBYTE(data);
340 /* store ASCII char in buffer */
341 buffer[len++] = LOBYTE(data);
343 } else {
344 /* we're not in raw mode, so we need to do line input... */
345 while (TRUE) {
346 WORD data;
347 /* check for new keyboard input */
348 while (CurOfs == bios->FirstKbdCharPtr) {
349 /* no input available yet, so wait... */
350 DOSVM_Wait( ctx );
352 /* read from keyboard queue (call int16?) */
353 data = ((WORD*)bios)[CurOfs];
354 CurOfs += 2;
355 if (CurOfs >= bios->KbdBufferEnd) CurOfs = bios->KbdBufferStart;
356 bios->NextKbdCharPtr = CurOfs;
358 if (LOBYTE(data) == '\r') {
359 /* it's the return key, we're done */
360 linebuffer[len++] = LOBYTE(data);
361 break;
363 else if (LOBYTE(data) >= ' ') {
364 /* a character */
365 if ((len+1)<CON_BUFFER) {
366 linebuffer[len] = LOBYTE(data);
367 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &linebuffer[len++], 1, NULL, NULL);
369 /* else beep, but I don't like noise */
371 else switch (LOBYTE(data)) {
372 case '\b':
373 if (len>0) {
374 len--;
375 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\b \b", 3, NULL, NULL);
377 break;
380 if (len > count) {
381 /* save rest of line for later */
382 lol->offs_unread_CON = linebuffer - (BYTE*)lol + count;
383 len = count;
385 memcpy(buffer, linebuffer, len);
387 hdr->status = STAT_DONE;
388 io->count = len;
390 break;
391 case CMD_SAFEINPUT:
392 if (curbuffer) {
393 /* some line input waiting */
394 hdr->status = STAT_DONE;
395 ((REQ_SAFEINPUT*)hdr)->data = *curbuffer;
397 else if (con->attr & ATTR_RAW) {
398 if (CurOfs == bios->FirstKbdCharPtr) {
399 /* no input */
400 hdr->status = STAT_DONE|STAT_BUSY;
401 } else {
402 /* some keyboard input waiting */
403 hdr->status = STAT_DONE;
404 ((REQ_SAFEINPUT*)hdr)->data = ((BYTE*)bios)[CurOfs];
406 } else {
407 /* no line input */
408 hdr->status = STAT_DONE|STAT_BUSY;
410 break;
411 case CMD_INSTATUS:
412 if (curbuffer) {
413 /* we have data */
414 hdr->status = STAT_DONE;
416 else if (con->attr & ATTR_RAW) {
417 if (CurOfs == bios->FirstKbdCharPtr) {
418 /* no input */
419 hdr->status = STAT_DONE|STAT_BUSY;
420 } else {
421 /* some keyboard input waiting */
422 hdr->status = STAT_DONE;
424 } else {
425 /* no line input */
426 hdr->status = STAT_DONE|STAT_BUSY;
429 break;
430 case CMD_INFLUSH:
431 /* flush line and keyboard queue */
432 lol->offs_unread_CON = 0;
433 bios->NextKbdCharPtr = bios->FirstKbdCharPtr;
434 break;
435 case CMD_OUTPUT:
436 case CMD_SAFEOUTPUT:
438 REQ_IO *io = (REQ_IO *)hdr;
439 BYTE *buffer = CTX_SEG_OFF_TO_LIN(ctx,
440 SELECTOROF(io->buffer),
441 (DWORD)OFFSETOF(io->buffer));
442 DWORD result = 0;
443 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, io->count, &result, NULL);
444 io->count = result;
445 hdr->status = STAT_DONE;
447 break;
448 default:
449 hdr->status = STAT_DONE;
451 do_lret(ctx);
454 static void InitListOfLists(DOS_LISTOFLISTS *DOS_LOL)
457 Output of DOS 6.22:
459 0133:0020 6A 13-33 01 CC 00 33 01 59 00 j.3...3.Y.
460 0133:0030 70 00 00 00 72 02 00 02-6D 00 33 01 00 00 2E 05 p...r...m.3.....
461 0133:0040 00 00 FC 04 00 00 03 08-92 21 11 E0 04 80 C6 0D .........!......
462 0133:0050 CC 0D 4E 55 4C 20 20 20-20 20 00 00 00 00 00 00 ..NUL ......
463 0133:0060 00 4B BA C1 06 14 00 00-00 03 01 00 04 70 CE FF .K...........p..
464 0133:0070 FF 00 00 00 00 00 00 00-00 01 00 00 0D 05 00 00 ................
465 0133:0080 00 FF FF 00 00 00 00 FE-00 00 F8 03 FF 9F 70 02 ..............p.
466 0133:0090 D0 44 C8 FD D4 44 C8 FD-D4 44 C8 FD D0 44 C8 FD .D...D...D...D..
467 0133:00A0 D0 44 C8 FD D0 44 .D...D
469 DOS_LOL->CX_Int21_5e01 = 0x0;
470 DOS_LOL->LRU_count_FCB_cache = 0x0;
471 DOS_LOL->LRU_count_FCB_open = 0x0;
472 DOS_LOL->OEM_func_handler = -1; /* not available */
473 DOS_LOL->INT21_offset = 0x0;
474 DOS_LOL->sharing_retry_count = 3;
475 DOS_LOL->sharing_retry_delay = 1;
476 DOS_LOL->ptr_disk_buf = 0x0;
477 DOS_LOL->offs_unread_CON = 0x0;
478 DOS_LOL->seg_first_MCB = 0x0;
479 DOS_LOL->ptr_first_DPB = 0x0;
480 DOS_LOL->ptr_first_SysFileTable = 0x0;
481 DOS_LOL->ptr_clock_dev_hdr = 0x0;
482 DOS_LOL->ptr_CON_dev_hdr = 0x0;
483 DOS_LOL->max_byte_per_sec = 512;
484 DOS_LOL->ptr_disk_buf_info = 0x0;
485 DOS_LOL->ptr_array_CDS = 0x0;
486 DOS_LOL->ptr_sys_FCB = 0x0;
487 DOS_LOL->nr_protect_FCB = 0x0;
488 DOS_LOL->nr_block_dev = 0x0;
489 DOS_LOL->nr_avail_drive_letters = 26; /* A - Z */
490 DOS_LOL->nr_drives_JOINed = 0x0;
491 DOS_LOL->ptr_spec_prg_names = 0x0;
492 DOS_LOL->ptr_SETVER_prg_list = 0x0; /* no SETVER list */
493 DOS_LOL->DOS_HIGH_A20_func_offs = 0x0;
494 DOS_LOL->PSP_last_exec = 0x0;
495 DOS_LOL->BUFFERS_val = 99; /* maximum: 99 */
496 DOS_LOL->BUFFERS_nr_lookahead = 8; /* maximum: 8 */
497 DOS_LOL->boot_drive = 3; /* C: */
498 DOS_LOL->flag_DWORD_moves = 0x01; /* i386+ */
499 DOS_LOL->size_extended_mem = 0xf000; /* very high value */
502 void DOSDEV_InstallDOSDevices(void)
504 DOS_DATASEG *dataseg;
505 WORD seg;
506 WORD selector;
507 unsigned int n;
509 /* allocate DOS data segment or something */
510 dataseg = DOSVM_AllocDataUMB( sizeof(DOS_DATASEG), &seg, &selector );
512 DOS_LOLSeg = MAKESEGPTR( seg, 0 );
513 DOSMEM_LOL()->wine_rm_lol =
514 MAKESEGPTR( seg, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) );
515 DOSMEM_LOL()->wine_pm_lol =
516 MAKESEGPTR( selector, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) );
518 /* initialize the magnificent List Of Lists */
519 InitListOfLists(&dataseg->lol);
521 /* Set up first device (NUL) */
522 dataseg->lol.NUL_dev.next_dev = MAKESEGPTR(seg, DOS_DATASEG_OFF(dev[0]));
523 dataseg->lol.NUL_dev.attr = devs[0].attr;
524 dataseg->lol.NUL_dev.strategy = DOS_DATASEG_OFF(thunk[0].ljmp1);
525 dataseg->lol.NUL_dev.interrupt = DOS_DATASEG_OFF(thunk[0].ljmp2);
526 memcpy(dataseg->lol.NUL_dev.name, devs[0].name, 8);
528 /* Set up the remaining devices */
529 for (n = 1; n < NR_DEVS; n++)
531 dataseg->dev[n-1].next_dev = (n+1) == NR_DEVS ? NONEXT :
532 MAKESEGPTR(seg, DOS_DATASEG_OFF(dev[n]));
533 dataseg->dev[n-1].attr = devs[n].attr;
534 dataseg->dev[n-1].strategy = DOS_DATASEG_OFF(thunk[n].ljmp1);
535 dataseg->dev[n-1].interrupt = DOS_DATASEG_OFF(thunk[n].ljmp2);
536 memcpy(dataseg->dev[n-1].name, devs[n].name, 8);
539 /* Set up thunks */
540 for (n = 0; n < NR_DEVS; n++)
542 dataseg->thunk[n].ljmp1 = LJMP;
543 dataseg->thunk[n].strategy = (RMCBPROC)DPMI_AllocInternalRMCB(devs[n].strategy);
544 dataseg->thunk[n].ljmp2 = LJMP;
545 dataseg->thunk[n].interrupt = (RMCBPROC)DPMI_AllocInternalRMCB(devs[n].interrupt);
548 /* CON is device 1 */
549 dataseg->lol.ptr_CON_dev_hdr = MAKESEGPTR(seg, DOS_DATASEG_OFF(dev[0]));
552 DWORD DOSDEV_Console(void)
554 return DOSMEM_LOL()->ptr_CON_dev_hdr;
557 DWORD DOSDEV_FindCharDevice(char*name)
559 SEGPTR cur_ptr = MAKESEGPTR(HIWORD(DOS_LOLSeg), FIELD_OFFSET(DOS_LISTOFLISTS,NUL_dev));
560 DOS_DEVICE_HEADER *cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr));
561 char dname[8];
562 int cnt;
564 /* get first 8 characters */
565 strncpy(dname,name,8);
566 /* if less than 8 characters, pad with spaces */
567 for (cnt=0; cnt<8; cnt++)
568 if (!dname[cnt]) dname[cnt]=' ';
570 /* search for char devices with the right name */
571 while (cur &&
572 ((!(cur->attr & ATTR_CHAR)) ||
573 memcmp(cur->name,dname,8))) {
574 cur_ptr = cur->next_dev;
575 if (cur_ptr == NONEXT) cur=NULL;
576 else cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr));
578 return cur_ptr;
581 static void DOSDEV_DoReq(void*req, DWORD dev)
583 REQUEST_HEADER *hdr = (REQUEST_HEADER *)req;
584 DOS_DEVICE_HEADER *dhdr;
585 CONTEXT86 ctx;
586 char *phdr;
588 dhdr = PTR_REAL_TO_LIN(SELECTOROF(dev),OFFSETOF(dev));
589 phdr = ((char*)DOSMEM_LOL()) + DOS_DATASEG_OFF(req);
591 /* copy request to request scratch area */
592 memcpy(phdr, req, hdr->size);
594 /* prepare to call device driver */
595 memset(&ctx, 0, sizeof(ctx));
596 ctx.EFlags |= V86_FLAG;
598 /* ES:BX points to request for strategy routine */
599 ctx.SegEs = HIWORD(DOS_LOLSeg);
600 ctx.Ebx = DOS_DATASEG_OFF(req);
602 /* call strategy routine */
603 ctx.SegCs = SELECTOROF(dev);
604 ctx.Eip = dhdr->strategy;
605 DPMI_CallRMProc(&ctx, 0, 0, 0);
607 /* call interrupt routine */
608 ctx.SegCs = SELECTOROF(dev);
609 ctx.Eip = dhdr->interrupt;
610 DPMI_CallRMProc(&ctx, 0, 0, 0);
612 /* completed, copy request back */
613 memcpy(req, phdr, hdr->size);
615 if (hdr->status & STAT_ERROR) {
616 switch (hdr->status & STAT_MASK) {
617 case 0x0F: /* invalid disk change */
618 /* this error seems to fit the bill */
619 SetLastError(ERROR_NOT_SAME_DEVICE);
620 break;
621 default:
622 SetLastError((hdr->status & STAT_MASK) + 0x13);
623 break;
628 static int DOSDEV_IO(unsigned cmd, DWORD dev, DWORD buf, int buflen)
630 REQ_IO req;
632 req.hdr.size=sizeof(req);
633 req.hdr.unit=0; /* not dealing with block devices yet */
634 req.hdr.command=cmd;
635 req.hdr.status=STAT_BUSY;
636 req.media=0; /* not dealing with block devices yet */
637 req.buffer=buf;
638 req.count=buflen;
639 req.sector=0; /* block devices */
640 req.volume=0; /* block devices */
642 DOSDEV_DoReq(&req, dev);
644 return req.count;
647 int DOSDEV_Peek(DWORD dev, BYTE*data)
649 REQ_SAFEINPUT req;
651 req.hdr.size=sizeof(req);
652 req.hdr.unit=0; /* not dealing with block devices yet */
653 req.hdr.command=CMD_SAFEINPUT;
654 req.hdr.status=STAT_BUSY;
655 req.data=0;
657 DOSDEV_DoReq(&req, dev);
659 if (req.hdr.status & STAT_BUSY) return 0;
661 *data = req.data;
662 return 1;
665 int DOSDEV_Read(DWORD dev, DWORD buf, int buflen)
667 return DOSDEV_IO(CMD_INPUT, dev, buf, buflen);
670 int DOSDEV_Write(DWORD dev, DWORD buf, int buflen, int verify)
672 return DOSDEV_IO(verify?CMD_SAFEOUTPUT:CMD_OUTPUT, dev, buf, buflen);
675 int DOSDEV_IoctlRead(DWORD dev, DWORD buf, int buflen)
677 return DOSDEV_IO(CMD_INIOCTL, dev, buf, buflen);
680 int DOSDEV_IoctlWrite(DWORD dev, DWORD buf, int buflen)
682 return DOSDEV_IO(CMD_OUTIOCTL, dev, buf, buflen);
685 void DOSDEV_SetSharingRetry(WORD delay, WORD count)
687 DOSMEM_LOL()->sharing_retry_delay = delay;
688 if (count) DOSMEM_LOL()->sharing_retry_count = count;
691 SEGPTR DOSDEV_GetLOL(BOOL v86)
693 if (v86) return DOSMEM_LOL()->wine_rm_lol;
694 else return DOSMEM_LOL()->wine_pm_lol;