summaryrefslogblamecommitdiffstats
path: root/private/mvdm/softpc.new/bios/msbio1.asm
blob: e115bd0d0531e7e276a17eb3a4faa41f78a1c17e (plain) (tree)
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
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                    
	page	,160
	title	msbio1.asm - Bios_Data definition and device driver entry/exit

;
;----------------------------------------------------------------------------
;
; Modification history
;
; 26-Feb-1991  sudeepb	Ported for NT DOSEm
;
;----------------------------------------------------------------------------
;
	include version.inc	; set build flags
	include biosseg.inc	; define BIOS segments

	include	devsym.inc
	include	msequ.inc
	include vint.inc


; Assembly conditional for stack switching
;
STACKSW		equ	1

Bios_Data	segment

	assume	cs:Bios_Data
	public	BData_start
BData_start:


	assume	ds:nothing,es:nothing

	public	hdrv_pat
hdrv_pat label	word			; patched by msinit
	assume	cs:Bios_Data

	extrn	init:near		; this is in msinit

	jmp	init			; go to initialization code


;	define some stuff that is also used by msdos.sys from an include file

In_Bios	=	0ffffh	; define flag for msbdata.inc
	include	msbdata.inc


	public	inHMA,xms
inHMA	db	0		; flag indicates we're running from HMA
xms	dd	0		; entry point to xms if above is true

	align	4

	public	ntvdmstate
ntvdmstate  dd	0
IF 2
.errnz	ntvdmstate-BData_start-FIXED_NTVDMSTATE_OFFSET
ENDIF


	public	ptrsav
ptrsav	dd	0

	public	auxbuf
auxbuf	db	0,0,0,0   	;set of 1 byte buffers for com 1,2,3, and 4
	public	zeroseg
zeroseg dw	0		; easy way to load segment registers with zero

	public	auxnum
auxnum	dw	0			;which aux device was requested


	public	res_dev_list

res_dev_list	label	byte
	p_attr	=	chardev+outtilbusy+dev320+IOQUERY+DEVOPCL
; **	p_attr	=	chardev+outtilbusy+dev320

	sysdev <auxdev2,8013h,strategy,con_entry,'CON     '>
auxdev2 sysdev <prndev2,8000h,strategy,aux0_entry,'AUX     '>
prndev2 sysdev <timdev,p_attr,strategy,prn0_entry,'PRN     '>
timdev	sysdev <com1dev,8008h,strategy,tim_entry,'CLOCK$  '>
com1dev sysdev <lpt1dev,8000h,strategy,aux0_entry,'COM1    '>
lpt1dev sysdev <lpt2dev,p_attr,strategy,prn1_entry,"LPT1    ">
lpt2dev sysdev <lpt3dev,p_attr,strategy,prn2_entry,"LPT2    ">
lpt3dev sysdev <com2dev,p_attr,strategy,prn3_entry,"LPT3    ">
com2dev sysdev <com3dev,8000h,strategy,aux1_entry,"COM2    ">
com3dev sysdev <com4dev,8000h,strategy,aux2_entry,"COM3    ">
com4dev dw	-1,Bios_Data,8000h,strategy,aux3_entry
	db	"COM4    "


		public	RomVectors
RomVectors	label	byte
	public	Old10,	Old15, Old19, Old1B
	db	10h					; M028
Old10	dd	(?)					; M028
	db	15h
Old15	dd	(?)
	db	19h
Old19	dd	(?)
	db	1bh
Old1B	dd	(?)
EndRomVectors	equ	$
		public	NUMROMVECTORS
NUMROMVECTORS	equ	((EndRomVectors - RomVectors)/5)

	public	spc_mse_int10
spc_mse_int10	dd	(?)

	public	int29Perf
int29Perf	dd	(?)


	public	keyrd_func
	public	keysts_func

; moved altah to inc\msbdata.inc so it could go in instance table in DOS

keyrd_func	db	0	; default is conventional keyboard read
keysts_func	db	1	; default is conventional keyboard status check.

	public printdev
printdev	db	0		; index into above array

		public	multrk_flag
multrk_flag	dw	0

; the following variable can be modified via ioctl sub-function 16. in this
; way, the wait can be set to suit the speed of the particular printer being
; used. one for each printer device.

	public wait_count
wait_count	dw	4 dup (50h)	; array of retry counts for printer

	public	int19sem
int19sem db	0			; indicate that all int 19
					; initialization is complete

;	we assume the following remain contiguous and their order doesn't change
i19_lst:
	irp	aa,<02,08,09,0a,0b,0c,0d,0e,70,72,73,74,76,77>
	public	int19old&aa
		db	aa&h	; store the number as a byte
int19old&aa	dd	-1	;orignal hardware int. vectors for int 19h.
	endm

num_i19 =	((offset $) - (offset i19_lst))/5


;variables for dynamic relocatable modules
;these should be stay resident.

	public	int6c_ret_addr
int6c_ret_addr	dd	?		; return address from int 6c for p12 machine

;
;   data structures for real-time date and time
;
	public	bin_date_time
	public	month_table
	public	daycnt2
	public	feb29

bin_date_time:
	db	0		; century (19 or 20) or hours (0-23)
	db	0		; year in century (0...99) or minutes (0-59)
	db	0		; month in year (1...12) or seconds (0-59)
	db	0		; day in month (1...31)

month_table:
	dw	0		; january
	dw	31		; february
	dw	59
	dw	90
	dw	120
	dw	151
	dw	181
	dw	212
	dw	243
	dw	273
	dw	304
	dw	334		; december
daycnt2 dw	0000		; temp for count of days since 1-1-80
feb29	db	0		; february 29 in a leap year flag


;************************************************************************
;*									*
;*	entry points into Bios_Code routines.  The segment values	*
;*	  are plugged in by seg_reinit.					*
;*									*
;************************************************************************

	public	cdev
cdev	dd	chardev_entry
bcode_i2f dd	i2f_handler
end_BC_entries:

;************************************************************************
;*									*
;*	cbreak - break key handling - simply set altah=3 and iret	*
;*									*
;************************************************************************

	public	cbreak
cbreak	proc	near
	assume	ds:nothing,es:nothing

	mov	altah,3		;indicate break key set

	public	intret		; general purpose iret in the Bios_Data seg
intret:
        FIRET
cbreak	endp

;************************************************************************
;*									*
;*	strategy - store es:bx (device driver request packet)		*
;*		     away at [ptrsav] for next driver function call	*
;*									*
;************************************************************************

	public	strategy
strategy proc	far
	assume	ds:nothing,es:nothing

	mov	word ptr cs:[ptrsav],bx
	mov	word ptr cs:[ptrsav+2],es
	ret
strategy endp

;************************************************************************
;*									*
;*	device driver entry points.  these are the initial		*
;*	  'interrupt' hooks out of the device driver chain.		*
;*	  in the case of our resident drivers, they'll just		*
;*	  stick a fake return address on the stack which		*
;*	  points to dispatch tables and possibly some unit		*
;*	  numbers, and then call through a common entry point		*
;*	  which can take care of a20 switching				*
;*									*
;************************************************************************

con_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry	; call into code segment handler
	dw	con_table

con_entry endp

;--------------------------------------------------------------------

prn0_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	prn_table
	db	0,0		; device numbers

prn0_entry endp

;--------------------------------------------------------------------

prn1_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	prn_table
	db	0,1

prn1_entry endp

;--------------------------------------------------------------------

prn2_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	prn_table
	db	1,2

prn2_entry endp

;--------------------------------------------------------------------

prn3_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	prn_table
	db	2,3

prn3_entry endp

;--------------------------------------------------------------------

aux0_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	aux_table
	db	0

aux0_entry endp

;--------------------------------------------------------------------

aux1_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	aux_table
	db	1

aux1_entry endp

;--------------------------------------------------------------------

aux2_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	aux_table
	db	2

aux2_entry endp

;--------------------------------------------------------------------

aux3_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	aux_table
	db	3

aux3_entry endp

;--------------------------------------------------------------------

tim_entry proc	near
	assume	ds:nothing,es:nothing

	call	cdev_entry
	dw	tim_table

tim_entry endp

;--------------------------------------------------------------------

;************************************************************************
;*									*
;*	Ensure A20 is enabled before jumping into code in HMA.		*
;*	This code assumes that if Segment of Device request packet is	*
;*	DOS DATA segment then the Device request came from DOS & that	*
;*	A20 is already on.						*
;*									*
;************************************************************************

cdev_entry proc	near
	assume	ds:nothing,es:nothing
;
; M064 - BEGIN
;
	cmp	inHMA, 0
	je	ce_enter_codeseg; optimized for DOS in HMA

	push	ax
	mov	ax, DosDataSg
	cmp	word ptr [ptrsav+2], ax
	pop	ax
	jne	not_from_dos	; jump is coded this way to fall thru
				;	in 99.99% of the cases
ce_enter_codeseg:
	jmp	cdev
not_from_dos:
	call	EnsureA20On
;
; M064 - END
;
	jmp	short ce_enter_codeseg
cdev_entry endp

;************************************************************************
;*									*
;*	outchr - this is our int 29h handler.  it writes the		*
;*	   character in al on the display using int 10h ttywrite	*
;*									*
;************************************************************************

	public	outchr
outchr	proc	far
	assume	ds:nothing,es:nothing

	push	ax
	push	si
	push	di
	push	bp
	push	bx
	mov	ah,0eh		; set command to write a character
	mov	bx,7		; set foreground color
	int	10h		; call rom-bios
	pop	bx
	pop	bp
	pop	di
	pop	si
	pop	ax
        jmp     intret
outchr	endp

; M001 - BEGIN

;************************************************************************
;*									*
;*	EnsureA20On - ensure that a20 is enabled if we're running	*
;*	  in the HMA before interrupt entry points into Bios_Code	*
;*									*
;************************************************************************

HiMem	label	dword
	dw	90h
	dw	0ffffh

LoMem	label	dword
	dw	80h
	dw	0h

EnsureA20On	proc near
	assume	ds:nothing,es:nothing
	call	IsA20Off
	jz	ea_enable
	ret

EnableA20	proc	near	; M041
ea_enable:
	push	ax
	push	bx
	mov	ah,5		; localenablea20
	call	xms
	pop	bx
	pop	ax
bie_done:
	ret
EnableA20	endp		; M041

EnsureA20On	endp
;
; M001 - END

; M041 : BEGIN
;
;----------------------------------------------------------------------------
;
; procedure : IsA20Off
;
;----------------------------------------------------------------------------
;
IsA20Off	proc	near
		push	ds
		push	es
		push	cx
		push	si
		push	di
		lds	si, HiMem
		les	di, LoMem
		mov	cx, 8
		rep	cmpsw
		pop	di
		pop	si
		pop	cx
		pop	es
		pop	ds
		ret
IsA20Off	endp

;
;----------------------------------------------------------------------------
;
; procedure : DisableA20
;
;----------------------------------------------------------------------------
;
DisableA20	proc	near
		push	ax
		push	bx
		mov	ah,6		; localdisable a20
		call	xms
		pop	bx
		pop	ax
		ret
DisableA20	endp

; M041 : END

;************************************************************************
;*									*
;*	int19 - bootstrap interrupt -- we must restore a bunch of the	*
;*	  interrupt vectors before resuming the original int19 code	*
;*									*
;************************************************************************


	public	int19
int19	proc	far
	assume	ds:nothing,es:nothing

	push	cs
	pop	ds
	assume	ds:Bios_Data

	mov	es,zeroseg

	mov	cx, NUMROMVECTORS	; no. of rom vectors to be restored
	mov	si, offset RomVectors	; point to list of saved vectors
next_int:
	lodsb				; get int number
	cbw				; assume < 128
	shl	ax, 1
	shl	ax, 1			; int * 4
	mov	di, ax
	lodsw
	stosw
	lodsw
	stosw				; install the saved vector
	loop	next_int

	cmp	byte ptr int19sem,0	; don't do the others unless we
	jz	doint19			; set our initialization complete flag

;	stacks code has changed these hardware interrupt vectors
;	stkinit in sysinit1 will initialize int19holdxx values.

	mov	si,offset i19_lst
	mov	cx,num_i19

i19_restore_loop:
	lodsb			; get interrupt number
	cbw			; assume < 128
	mov	di,ax		; save interrupt number
	lodsw			; get original vector offset
	mov	bx,ax		; save it
	lodsw			; get original vector segment
	cmp	bx,-1		; check for 0ffffh (unlikely segment)
	jz	i19_restor_1	;opt no need to check selector too
	cmp	ax,-1		;opt 0ffffh is unlikely offset
	jz	i19_restor_1

	add	di,di
	add	di,di
	xchg	ax,bx
	stosw
	xchg	ax,bx
	stosw			; put the vector back

i19_restor_1:
	loop	i19_restore_loop

doint19:
	int	19h
int19	endp
;
; M036 - BEGIN
;
;
;----------------------------------------------------------------------------
;
; procedure : int15
;
;		Int15 handler for recognizing ctrl-alt-del seq.
;
;----------------------------------------------------------------------------
;
DELKEY		equ	53h
	public	Int15
Int15	proc	far
	assume	ds:nothing
	cmp	ax, (4fh shl 8) + DELKEY	; del keystroke ?
	je	@f
	jmp	dword ptr Old15			
@@:
	stc
	jmp	dword ptr Old15
Int15	endp
;
;
;************************************************************************
;*									*
;*	the int2f handler chains up to Bios_Code through here.		*
;*	  it returns through one of the three functions that follow.	*
;*	  notice that we'll assume we're being entered from DOS, so	*
;*	  that we're guaranteed to be A20 enabled if needed		*
;*									*
;************************************************************************

int_2f	proc	far
	assume	ds:nothing,es:nothing
	jmp	bcode_i2f
int_2f	endp



;************************************************************************
;*									*
;*	re_init - called back by sysinit after a bunch of stuff		*
;*		is done.  presently does nothing.  affects no		*
;*		registers!						*
;*									*
;************************************************************************

	public	re_init
re_init proc	far
	assume	ds:nothing,es:nothing
	ret
re_init endp


;SR; WIN386 support
; WIN386 instance data structure
;
;
; Here is a Win386 startup info structure which we set up and to which
; we return a pointer when Win386 initializes.
;

public	Win386_SI, SI_Version, SI_Next

Win386_SI	label	byte		; Startup Info for Win386
SI_Version	db	3, 0		; for Win386 3.0
SI_Next		dd	?		; pointer to next info structure
		dd	0		; a field we don't need
		dd	0		; another field we don't need
SI_Instance	dw	Instance_Table, Bios_Data ; far pointer to instance table

;
; This table gives Win386 the instance data in the BIOS and ROM-BIOS data
; areas.  Note that the address and size of the hardware stacks must
; be calculated and inserted at boot time.
;
Instance_Table	label	dword
	dw	00H, 50H		; print screen status...
	dw	02			; ...2 bytes
	dw	0Eh, 50H		; ROM Basic data...
	dw	14H			; ...14H bytes
	dw	ALTAH, Bios_Data	; a con device buffer...
	dw	01			; ... 1 byte
IF STACKSW
public NextStack
NextStack	label dword

;	NOTE:  If stacks are disabled by STACKS=0,0, the following
;		instance items WILL NOT be filled in by SYSINIT.
;		That's just fine as long as these are the last items
;		in the instance list since the first item is initialized
;		to 0000 at load time.

	dw	0, 0		; pointer to next stack to be used...
	dw	02			; ...2 bytes
; The next item in the instance table must be filled in at sysinit time
public IT_StackLoc, IT_StackSize
IT_StackLoc	dd	?		; location of hardware stacks
IT_StackSize	dw	?		; size of hardware stacks
ENDIF
	dd	0			; terminate the instance table

;SR;
; Flag to indicate whether Win386 is running or not
;
public	IsWin386
IsWin386		db	0

;
;This routine was originally in BIOS_CODE but this causes a lot of problems
;when we call it including checking of A20. The code being only about
;30 bytes, we might as well put it in BIOS_DATA
;
PUBLIC	V86_Crit_SetFocus

V86_Crit_SetFocus	PROC	FAR

			push	di
			push	es
			push	bx
			push	ax

			xor	di,di
			mov	es,di
			mov	bx,0015h	;Device ID of DOSMGR device
			mov	ax,1684h	;Get API entry point
			int	2fh
			mov	ax,es
			or	ax,di		
			jz	Skip
;
;Here, es:di is address of API routine. Set up stack frame to simulate a call
;
			push	cs		;push return segment
			mov	ax,OFFSET Skip
			push	ax		;push return offset
			push	es
			push	di		;API far call address
			mov	ax,1		;SetFocus function number
			retf			;do the call
Skip:
			pop	ax
			pop	bx
			pop	es
			pop	di
			ret
V86_Crit_SetFocus	ENDP



;
;End WIN386 support
;

		public	FreeHMAPtr
		public	MoveDOSIntoHMA
FreeHMAPtr	dw	-1
MoveDOSIntoHMA	dd	sysinitseg:FTryToMovDOSHi


;SR;
; A communication block has been setup between the DOS and the BIOS. All
;the data starting from SysinitPresent will be part of the data block.
;Right now, this is the only data being communicated. It can be expanded
;later to add more stuff
;
		public	SysinitPresent
		public	DemInfoFlag
SysinitPresent	db	0
DemInfoFlag     db      0


; this will be the end of the BIOS data if no hard disks are in system

	public	endBIOSData
endBIOSData label byte

Bios_Data ends

;
;	okay.  so much for Bios_Data.  Now let's put our device driver
;	  entry stuff up into Bios_Code.

Bios_Code	segment
	assume	cs:Bios_Code

; ORG a bit past zero to leave room for running in HMA...

	org	30h
	public	BCode_start
BCode_start:

;	device driver entry point tables

	extrn	con_table:near
	extrn	tim_table:near
	extrn	prn_table:near
	extrn	aux_table:near

	extrn	i2f_handler:far

	public	Bios_Data_Word
Bios_Data_Word	dw	Bios_Data

;************************************************************************
;*									*
;*	seg_reinit is called with ax = our new code segment value,	*
;*	  trashes di, cx, es						*
;*									*
;*	cas -- should be made disposable!				*
;*									*
;************************************************************************

	public	seg_reinit
seg_reinit	proc	far
	assume	ds:nothing,es:nothing

	mov	es,Bios_Data_Word
	assume	es:Bios_Data
	mov	di,2+offset cdev
	mov	cx,((offset end_BC_entries) - (offset cdev))/4

seg_reinit_1:
	stosw				; modify Bios_Code entry points
	inc	di
	inc	di
	loop	seg_reinit_1
	ret
seg_reinit	endp

;************************************************************************
;*									*
;*	chardev_entry - main device driver dispatch routine		*
;*	   called with a dummy parameter block on the stack		*
;*	   dw dispatch_table, dw prn/aux numbers (optional)		*
;*									*
;*	will eventually take care of doing the transitions in		*
;*	   out of Bios_Code						*
;*									*
;************************************************************************

chardev_entry	proc	far
	assume	ds:nothing,es:nothing

	push	si
	push	ax
	push	cx
	push	dx
	push	di
	push	bp
	push	ds
	push	es
	push	bx
	mov	bp,sp			; point to stack frame
	mov	si,18[bp]		; get return address (dispatch table)
	mov	ds,Bios_Data_Word	;  load ds: -> Bios_Data
	assume	ds:Bios_Data
	mov	ax,word ptr 2[si]	; get the device number if present
	mov	byte ptr [auxnum],al
	mov	byte ptr [printdev],ah
	mov	si,word ptr [si]	; point to the device dispatch table

	les	bx,[ptrsav]		;get pointer to i/o packet

	mov	al,byte ptr es:[bx].unit	;al = unit code
	mov	ah,byte ptr es:[bx].media	;ah = media descrip
	mov	cx,word ptr es:[bx].count	;cx = count
	mov	dx,word ptr es:[bx].start	;dx = start sector

	xchg	di,ax
	mov	al,byte ptr es:[bx].cmd
	cmp	al,cs:[si]
	jae	command_error

	cbw				; note that al <= 15 means ok
	shl	ax,1

	add	si,ax
	xchg	ax,di

	les	di,dword ptr es:[bx].trans

	cld				; ***** always clear direction
	call	cs:word ptr [si+1] 	;go do command
	assume	ds:nothing

	jc	already_got_ah_status	; if function returned status, don't
	mov	ah,1			;  load with normal completion

already_got_ah_status:
	mov	ds,Bios_Data_Word	; cas///// note: shouldn't be needed!
	assume	ds:Bios_Data
	lds	bx,[ptrsav]
	assume	ds:nothing
	mov	word ptr [bx].status,ax ;mark operation complete

	pop	bx
	pop	es
	pop	ds
	pop	bp
	pop	di
	pop	dx
	pop	cx
	pop	ax
	pop	si
	add	sp,2		; get rid of fake return address

chardev_entry endp		; fall through into bc_retf

	public	bc_retf
bc_retf	proc	far
	assume	ds:nothing,es:nothing

	ret

bc_retf	endp


command_error:
	call	bc_cmderr
	jmp	short already_got_ah_status

;
;----------------------------------------------------------------------------
; The following piece of hack is for supporting CP/M compatibility
; Basically at offset 5 we have a far call into 0:c0. But this does not call
; 0:c0 directly instead it call f01d:fef0, because it needs to support 'lhld 6'
; The following hack has to reside at ffff:d0 (= f01d:fef0) if BIOS is loaded
; high.
;----------------------------------------------------------------------------


; BUGBUG sudeepb 21-May-1991 ; We can save these 30 bytes by moving
; off_d0 to right place.

	db	1fh dup (?)	; pad to bring offset to 0d0h

if2
	if ( offset off_d0 - 0d0h )
		%out CP/M compatibilty broken!!!
		%out Please re-pos hack to ffff:d0
	endif
endif

	public	off_d0
off_d0	db	5 dup (?)	; 5 bytes from 0:c0 will be copied onto here
				;  which is the CP/M call 5 entry point
	.errnz (offset off_d0 - 0d0h)


;----------------------------------------------------------
;
;	exit - all routines return through this path
;

	public	bc_cmderr
bc_cmderr:
	mov	al,3			;unknown command error

;	now zero the count field by subtracting its current value,
;	  which is still in cx, from itself.


;	subtract the number of i/o's NOT YET COMPLETED from total
;	  in order to return the number actually complete


	public	bc_err_cnt
bc_err_cnt:
	assume	ds:Bios_Data
	les	bx,[ptrsav]
	assume	es:nothing
	sub	es:word ptr [bx].count,cx;# of successful i/o's
	mov	ah,81h			;mark error return
	stc				; indicate abnormal end
	ret

Bios_Code	ends


;	the last real segment is sysinitseg

sysinitseg	segment
	assume	cs:sysinitseg
	extrn	FTryToMovDOSHi:far
	public	SI_start
SI_start:
sysinitseg	ends

	end