summaryrefslogtreecommitdiff
path: root/v4.0/src/DOS/MS_CODE.ASM
blob: 1bdd4af476edff67da226d90481c6285b5a1e120 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
;	SCCSID = @(#)mscode.asm 1.2 85/07/23
;
; MSCODE.ASM -- MSDOS code
;

.xlist
.xcref
include dossym.inc
include devsym.inc
include dosseg.asm
include ifssym.inc
include fastopen.inc
include fastxxxx.inc
.cref
.list

AsmVars <Kanji, Debug>

CODE	SEGMENT BYTE PUBLIC 'CODE'

ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

    I_need  InDos,BYTE			; TRUE => we are in dos, no interrupt
    I_need  OpenBuf,128 		; temp name buffer
    I_need  ExtErr,WORD 		; extended error code
    I_need  User_SS,WORD		; stack segment from user
    I_need  User_SP,WORD		; stack pointer from user
    I_need  DskStack,BYTE		; stack segment inside DOS
    I_need  ThisCDS,DWORD		; Currently referenced CDS pointer
    I_need  ThisDPB,DWORD		; Currently referenced DPB pointer
    I_need  Err_Table_21		; allowed return map table for errors
    I_need  FailErr,BYTE		; TRUE => system call is being failed
    I_need  ExtErr_Action,BYTE		; recommended action
    I_need  ExtErr_Class,BYTE		; error classification
    I_need  ExtErr_Locus,BYTE		; error location
    I_need  I21_Map_E_Tab,BYTE		; mapping extended error table
    I_need  User_In_AX,WORD		; initial input user AX
    I_need  FOO,WORD			; return address for dos 2f dispatch
    I_need  DTAB,WORD			; dos 2f dispatch table
    I_need  HIGH_SECTOR,WORD		; >32mb
    I_need  IFS_DRIVER_ERR,WORD 	; >32mb
    I_need  FastOpenFlg,BYTE		;
    I_need  FastSeekFlg,BYTE		;
    I_need  CURSC_DRIVE,BYTE		;

BREAK <NullDev -- Driver for null device>

procedure   SNULDEV,FAR
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
	OR	ES:[BX.REQSTAT],STDON	; Set done bit
entry INULDEV
	RET				; MUST NOT BE A RETURN!
EndProc SNULDEV

BREAK <AbsDRD, AbsDWRT -- INT int_disk_read, int_disk_write handlers>


TABLE	SEGMENT
Public MSC001S,MSC001E
MSC001S label byte
	IF	IBM
; Codes returned by BIOS
ERRIN:
	DB	2			; NO RESPONSE
	DB	6			; SEEK FAILURE
	DB	12			; GENERAL ERROR
	DB	4			; BAD CRC
	DB	8			; SECTOR NOT FOUND
	DB	0			; WRITE ATTEMPT ON WRITE-PROTECT DISK
ERROUT:
; DISK ERRORS RETURNED FROM INT 25 and 26
	DB	80H			; NO RESPONSE
	DB	40H			; Seek failure
	DB	2			; Address Mark not found
	DB	10H			; BAD CRC
	DB	4			; SECTOR NOT FOUND
	DB	3			; WRITE ATTEMPT TO WRITE-PROTECT DISK

NUMERR	EQU	$-ERROUT
	ENDIF
MSC001E label byte

TABLE	ENDS

;   AbsSetup - setup for abs disk functions

Procedure   AbsSetup,NEAR
	ASSUME	CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	INC	INDOS
	STI
	CLD
	PUSH	DS
	Context DS
	CALL	GETBP
	JC	errdriv 		;PM. error drive			;AN000;
	MOV	ES:[BP.dpb_free_cnt],-1 ; do not trust user at all.
errdriv:
	POP	DS
ASSUME	DS:NOTHING
	retc

	MOV	[HIGH_SECTOR],0 	;>32mb	from API			;AN000;
	CALL	RW32_CONVERT		;>32mb convert 32bit format to 16bit	;AN000;
	retc

	invoke	SET_RQ_SC_PARMS 	;LB. set up SC parms			;AN000;
	PUSH	DS
	PUSH	SI
	PUSH	AX
	Context DS
	MOV	SI,OFFSET DOSGROUP:OPENBUF
	MOV	[SI],AL
	ADD	BYTE PTR [SI],"A"
	MOV	WORD PTR [SI+1],003AH	; ":",0
	MOV	AX,0300H
	CLC
	INT	int_IBM 		; Will set carry if shared
	POP	AX
	POP	SI
	POP	DS
ASSUME	DS:NOTHING
	retnc
	MOV	ExtErr,error_not_supported
	return
EndProc AbsSetup

; Interrupt 25 handler.  Performs absolute disk read.
; Inputs:	AL - 0-based drive number
;		DS:BX point to destination buffer
;		CX number of logical sectors to read
;		DX starting  logical sector number (0-based)
; Outputs:	Original flags still on stack
;		Carry set
;		    AH error from BIOS
;		    AL same as low byte of DI from INT 24

	procedure   ABSDRD,FAR
	ASSUME	CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING

	CLI
	MOV	[user_SS],SS
	MOV	[user_SP],SP
	PUSH	CS
	POP	SS
ASSUME	SS:DOSGROUP
	MOV	SP,OFFSET DOSGROUP:DSKSTACK
	invoke	Save_World		      ;>32mb save all regs		;AN000;
	PUSH	ES
	CALL	AbsSetup
	JC	ILEAVE
if not ibmcopyright
; Here is a gross temporary fix to get around a serious design flaw in
;  the secondary cache.  The secondary cache does not check for media
;  changed (it should).  Hence, you can change disks, do an absolute
;  read, and get data from the previous disk.  To get around this,
;  we just won't use the secondary cache for absolute disk reads.
;                                                      -mw 8/5/88
	EnterCrit   critDisk
	MOV	[CURSC_DRIVE],-1	      ; invalidate SC			;AN000;
	LeaveCrit   critDisk
endif
	invoke	DSKREAD
TLEAVE:
	JZ	ILEAVE

	IF	IBM
; Translate the error code to ancient 1.1 codes
	PUSH	ES
	PUSH	CS
	POP	ES
	XOR	AH,AH			; Nul error code
	MOV	CX,NUMERR		; Number of possible error conditions
	MOV	DI,OFFSET DOSGROUP:ERRIN    ; Point to error conditions
	REPNE	SCASB
	JNZ	LEAVECODE		; Not found
	MOV	AH,ES:[DI+NUMERR-1]	; Get translation
LEAVECODE:
	POP	ES
	ENDIF
	MOV	[IFS_DRIVER_ERR],AX	;>32mb save error
	STC
ILEAVE:
	POP	ES
	invoke	Restore_World		     ;>32mb				;AN000;
	CLI
	DEC	INDOS
	MOV	SS,[user_SS]
ASSUME	SS:NOTHING
	MOV	SP,[user_SP]
	MOV	AX,[IFS_DRIVER_ERR]	     ;>32mb restore error		;AN000;
	STI
	RET				; This must not be a RETURN!
EndProc ABSDRD

; Interrupt 26 handler.  Performs absolute disk write.
; Inputs:	AL - 0-based drive number
;		DS:BX point to source buffer
;		CX number of logical sectors to write
;		DX starting  logical sector number (0-based)
; Outputs:	Original flags still on stack
;		Carry set
;		    AH error from BIOS
;		    AL same as low byte of DI from INT 24

	procedure   ABSDWRT,FAR
ASSUME	DS:NOTHING,ES:NOTHING,SS:NOTHING

	CLI
	MOV	[user_SS],SS
	MOV	[user_SP],SP
	PUSH	CS
	POP	SS
ASSUME	SS:DOSGROUP
	MOV	SP,OFFSET DOSGROUP:DSKSTACK
	invoke	Save_World		      ;>32mb save all regs		;AN000;

	PUSH	ES
	CALL	AbsSetup
	JC	ILEAVE

	EnterCrit   critDisk
	MOV	[CURSC_DRIVE],-1	      ; invalidate SC			;AN000;
	CALL	Fastxxx_Purge		      ; purge fatopen			;AN000;
	LeaveCrit   critDisk

	invoke	DSKWRITE
	JMP	TLEAVE
EndProc ABSDWRT

; Inputs:
;	AL = Logical unit number (A = 0)
; Function:
;	Find Drive Parameter Block
; Outputs:
;	ES:BP points to DPB
;	[THISDPB] = ES:BP
;	Carry set if unit number bad or unit is a NET device.
;		Later case sets extended error error_I24_not_supported
; No other registers altered

Procedure GETBP,NEAR
	DOSAssume   CS,<DS>,"GetBP"
	ASSUME	ES:NOTHING

	PUSH	AX
	ADD	AL,1			; No increment; need carry flag
	JC	SkipGet
	invoke	GetThisDrv
	JNC	SkipGet 		   ;PM. good drive			;AN000;
	XOR	AH,AH			   ;DCR. ax= error code 		;AN000;
	CMP	AX,error_not_dos_disk	   ;DCR. is unknown media ?		;AN000;
	JZ	SkipGet 		   ;DCR. yes, let it go 		;AN000;
	STC				   ;DCR.				;AN000;
	MOV	ExtErr,AX		   ;PM. invalid drive or Non DOS drive	;AN000;
	MOV	[IFS_DRIVER_ERR],0201H	   ;PM. other errors/unknown unit	;AN000;
SkipGet:
	POP	AX
	retc
	LES	BP,[THISCDS]
	TEST	ES:[BP.curdir_flags],curdir_isnet   ; Clears carry
	JZ	GETBP_CDS
	LES	BP,ES:[BP.curdir_ifs_hdr]	    ;IFS. if remote file	;AN000;
	TEST	ES:[BP.ifs_attribute],IFSREMOTE     ;IFS.			;AN000;
	LES	BP,[THISCDS]
	JZ	GETBP_CDS			    ;IFS. then error		;AN000;
	MOV	ExtErr,error_not_supported
	STC
	return

GETBP_CDS:
	LES	BP,ES:[BP.curdir_devptr]

	entry	GOTDPB
	DOSAssume   CS,<DS>,"GotDPB"
; Load THISDPB from ES:BP

	MOV	WORD PTR [THISDPB],BP
	MOV	WORD PTR [THISDPB+2],ES
	return
EndProc GetBP

BREAK <SYS_RET_OK SYS_RET_ERR CAL_LK ETAB_LK set system call returns>

ASSUME	SS:DOSGROUP

;
; These are the general system call exit mechanisms.  All internal system
; calls will transfer (jump) to one of these at the end.  Their sole purpose
; is to set the user's flags and set his AX register for return.
;

procedure   SYS_RETURN,NEAR
	ASSUME	DS:NOTHING,ES:NOTHING
entry	SYS_RET_OK
	invoke	FETCHI_CHECK		; TAG checking for FETCHI
	invoke	get_user_stack
	AND	[SI.user_F],NOT f_Carry ; turn off user's carry flag
	JMP	SHORT DO_RET		; carry is now clear

entry	SYS_RET_ERR
	XOR	AH,AH			; hack to allow for smaller error rets
	invoke	ETAB_LK 		; Make sure code is OK, EXTERR gets set
	CALL	ErrorMap
entry	From_GetSet
	invoke	get_user_stack
	OR	[SI.user_F],f_Carry	; signal carry to user
	STC				; also, signal internal error
DO_RET:
	MOV	[SI.user_AX],AX 	; Really only sets AH
	return

	entry	FCB_RET_OK
	entry	CPMFunc
	XOR	AL,AL
	return

	entry	FCB_RET_ERR
	XOR	AH,AH
	mov	exterr,AX
	CALL	ErrorMap
	MOV	AL,-1
	return

	entry	errorMap
	PUSH	SI
	MOV	SI,OFFSET DOSGROUP:ERR_TABLE_21
	CMP	[FAILERR],0		; Check for SPECIAL case.
	JZ	EXTENDED_NORMAL 	; All is OK.
	MOV	[EXTERR],error_FAIL_I24 ; Ooops, this is the REAL reason
	MOV	SI,OFFSET DOSGROUP:ERR_TABLE_21
EXTENDED_NORMAL:
	invoke	CAL_LK			; Set CLASS,ACTION,LOCUS for EXTERR
	POP	SI
	return

EndProc SYS_RETURN

; Inputs:
;	SI is OFFSET in DOSGROUP of CLASS,ACTION,LOCUS Table to use
;		(DS NEED not be DOSGROUP)
;	[EXTERR] is set with error
; Function:
;	Look up and set CLASS ACTION and LOCUS values for GetExtendedError
; Outputs:
;	[EXTERR_CLASS] set
;	[EXTERR_ACTION] set
;	[EXTERR_LOCUS] set  (EXCEPT on certain errors as determined by table)
; Destroys SI, FLAGS

	procedure   CAL_LK,NEAR
ASSUME	DS:NOTHING,ES:NOTHING

	PUSH	DS
	PUSH	AX
	PUSH	BX
	Context DS		; DS:SI -> Table
	MOV	BX,[EXTERR]	; Get error in BL
TABLK1:
	LODSB
	CMP	AL,0FFH
	JZ	GOT_VALS	; End of table
	CMP	AL,BL
	JZ	GOT_VALS	; Got entry
	ADD	SI,3		; Next table entry
	JMP	TABLK1

GOT_VALS:
	LODSW			; AL is CLASS, AH is ACTION
	CMP	AH,0FFH
	JZ	NO_SET_ACT
	MOV	[EXTERR_ACTION],AH     ; Set ACTION
NO_SET_ACT:
	CMP	AL,0FFH
	JZ	NO_SET_CLS
	MOV	[EXTERR_CLASS],AL      ; Set CLASS
NO_SET_CLS:
	LODSB			; Get LOCUS
	CMP	AL,0FFH
	JZ	NO_SET_LOC
	MOV	[EXTERR_LOCUS],AL
NO_SET_LOC:
	POP	BX
	POP	AX
	POP	DS
	return
EndProc CAL_LK

; Inputs:
;	AX is error code
;	[USER_IN_AX] has AH value of system call involved
; Function:
;	Make sure error code is appropriate to this call.
; Outputs:
;	AX MAY be mapped error code
;	[EXTERR] = Input AX
; Destroys ONLY AX and FLAGS

	procedure   ETAB_LK,NEAR
ASSUME	DS:NOTHING,ES:NOTHING

	PUSH	DS
	PUSH	SI
	PUSH	CX
	PUSH	BX
	Context DS
	MOV	[EXTERR],AX		; Set EXTERR with "real" error
	MOV	SI,OFFSET DOSGROUP:I21_MAP_E_TAB
	MOV	BH,AL			; Real code to BH
	MOV	BL,BYTE PTR [USER_IN_AX + 1]	; Sys call to BL
TABLK2:
	LODSW
	CMP	AL,0FFH 		; End of table?
	JZ	NOT_IN_TABLE		; Yes
	CMP	AL,BL			; Found call?
	JZ	GOT_CALL		; Yes
	XCHG	AH,AL			; Count to AL
	XOR	AH,AH			; Make word for add
	ADD	SI,AX			; Next table entry
	JMP	TABLK2

NOT_IN_TABLE:
	MOV	AL,BH			; Restore original code
	JMP	SHORT NO_MAP

GOT_CALL:
	MOV	CL,AH
	XOR	CH,CH			; Count of valid err codes to CX
CHECK_CODE:
	LODSB
	CMP	AL,BH			; Code OK?
	JZ	NO_MAP			; Yes
	LOOP	CHECK_CODE
NO_MAP:
	XOR	AH,AH			; AX is now valid code
	POP	BX
	POP	CX
	POP	SI
	POP	DS
	return

EndProc ETAB_LK

BREAK <DOS 2F Handler and default NET 2F handler>

IF installed

;
; SetBad sets up info for bad functions
;
Procedure   SetBad,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	MOV	AX,error_invalid_function	; ALL NET REQUESTS get inv func
	MOV	ExtErr_LOCUS,errLoc_UNK
	STC
	ret
EndProc SetBad
;
; BadCall is the initial routine for bad function calls
;
procedure   BadCall,FAR
	call	SetBad
	ret
EndProc BadCall
;
; OKCall always sets carry to off.
;
Procedure   OKCall,FAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	CLC
	ret
EndProc OKCall

; INT 2F handler works as follows:
;   PUSH    AX
;   MOV     AX,multiplex:function
;   INT     2F
;   POP     ...
; The handler itself needs to make the AX available for the various routines.

PUBLIC	Int2F
INT2F	PROC	FAR

INT2FNT:
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	STI
	CMP	AH,multNET
	JNZ	INT2FSHR
TestInstall:
	OR	AL,AL
	JZ	Leave2F
BadFunc:
	CALL	SetBad
	entry	Leave2F
	RET	2			; long return + clear flags off stack

INT2FSHR:
	CMP	AH,multSHARE		; is this a share request
	JZ	TestInstall		; yes, check for installation

INT2FNLS:
	CMP	AH,NLSFUNC		; is this a DOS 3.3 NLSFUNC request
	JZ	TestInstall		; yes check for installation

INT2FDOS:
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	CMP	AH,multDOS
	JZ	DispatchDOS
	IRET				; This assume that we are at the head
					; of the list
INT2F	ENDP

DispatchDOS:
	PUSH	FOO			; push return address
	PUSH	DTab			; push table address
	PUSH	AX			; push index
	PUSH	BP
	MOV	BP,SP
; stack looks like:
;   0	BP
;   2	DISPATCH
;   4	TABLE
;   6	RETURN
;   8	LONG-RETURN
;   c	FLAGS
;   e	AX

	MOV	AX,[BP+0Eh]		; get AX value
	POP	BP
	Invoke	TableDispatch
	JMP	BadFunc 		; return indicates invalid function

Procedure   INT2F_etcetera,NEAR
	entry	DosGetGroup
	PUSH	CS
	POP	DS
	return

	entry	DOSInstall
	MOV	AL,0FFh
	return
EndProc INT2F_etcetera

ENDIF
;Input: same as ABSDRD and ABSDWRT
;	 ES:BP -> DPB
;Functions: convert 32bit absolute RW input parms to 16bit input parms
;Output: carry set when CX=-1 and drive is less then 32mb
;	 carry clear, parms ok
;
Procedure   RW32_CONVERT,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	CMP	CX,-1			     ;>32mb  new format ?		;AN000;
	JZ	new32format		     ;>32mb  yes			;AN000;
	PUSH	AX			     ;>32mb  save ax			;AN000;
	PUSH	DX			     ;>32mb  save dx			;AN000;
	MOV	AX,ES:[BP.dpb_max_cluster]   ;>32mb  get max cluster #		;AN000;
	MOV	DL,ES:[BP.dpb_cluster_mask]  ;>32mb				;AN000;
	CMP	DL,0FEH 		     ;>32mb  removable ?		;AN000;
	JZ	letold			     ;>32mb  yes			;AN000;
	INC	DL			     ;>32mb				;AN000;
	XOR	DH,DH			     ;>32mb  dx = sector/cluster	;AN000;
	MUL	DX			     ;>32mb  dx:ax= max sector #	;AN000;
	OR	DX,DX			     ;>32mb  > 32mb ?			;AN000;
letold:
	POP	DX			     ;>32mb  retore dx			;AN000;
	POP	AX			     ;>32mb  restore ax 		;AN000;
	JZ	old_style		     ;>32mb  no 			;AN000;
	MOV	[IFS_DRIVER_ERR],0207H	     ;>32mb  error			;AN000;
	STC				     ;>32mb				;AN000;
	return				     ;>32mb				;AN000;
new32format:
	MOV	DX,WORD PTR [BX.SECTOR_RBA+2];>32mb				;AN000;
	MOV	[HIGH_SECTOR],DX	     ;>32mb				;AN000;
	MOV	DX,WORD PTR [BX.SECTOR_RBA]  ;>32mb				;AN000;
	MOV	CX,[BX.ABS_RW_COUNT]	     ;>32mb				;AN000;
	LDS	BX,[BX.BUFFER_ADDR]	     ;>32mb				;AN000;
old_style:				     ;>32mb				;AN000;
	CLC				     ;>32mb				;AN000;
	return				     ;>32mb				;AN000;
EndProc RW32_CONVERT


;Input: None
;Functions: Purge Fastopen/seek Cache Buffers
;Output: None
;
;
Procedure   Fastxxx_Purge,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
	PUSH	AX			      ; save regs.			;AN000;
	PUSH	SI								;AN000;
	PUSH	DX								;AN000;
	TEST	FastSeekflg,Fast_yes	      ; fastseek installed ?		;AN000;
	JZ	topen			      ; no				;AN000;
	MOV	AH,FastSeek_ID		      ; set fastseek id 		;AN000;
	JMP	SHORT dofast		      ; 				;AN000;
topen:
	TEST	FastOpenflg,Fast_yes	      ; fastopen installed ?		;AN000;
	JZ	nofast			      ; no				;AN000;
	MOV	AH,FastOpen_ID		      ; set fastseek installed		;AN000;
dofast:
	MOV	AL,FONC_purge		      ; purge				;AN000;
	MOV	DL,ES:[BP.dpb_drive]	      ; set up drive number		;AN000;
	invoke	Fast_Dispatch		      ; call fastopen/seek		;AN000;
nofast:
	POP	DX								;AN000;
	POP	SI			      ; restore regs			;AN000;
	POP	AX			      ; 				;AN000;

	return				      ; exit				;AN000;
EndProc Fastxxx_Purge

CODE	ENDS