-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathhead.asm
1478 lines (1273 loc) · 37.3 KB
/
head.asm
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
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
include defs.asm
; Copyright, 1988-1993, Russell Nelson, Crynwr Software
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
code segment word public
assume cs:code, ds:code
public phd_environ
org 2ch
phd_environ dw ?
public phd_dioa
org 80h
phd_dioa label byte
org 100h
start:
jmp start_1
extrn start_1: near
db "PK"
extrn branding_msg: byte
dw branding_msg
even ;put the stack on a word boundary.
dw 128 dup(?) ;128 words of stack.
our_stack label byte
extrn int_no: byte
public entry_point, sys_features, flagbyte, is_186, is_286, is_386
entry_point db ?,?,?,? ; interrupt to communicate.
sys_features db 0 ; 2h = MC 40h = 2nd 8259
is_186 db 0 ;=0 if 808[68], =1 if 80[123]86.
is_286 db 0 ;=0 if 80[1]8[68], =1 if 80[234]86.
is_386 db 0 ;=0 if 80[12]8[68], =1 if 80[34]86.
flagbyte db 0
original_mask db 0 ;=0 if interrupt was originally on.
even
functions label word
dw f_not_implemented ;0
dw f_driver_info ;1
dw f_access_type ;2
dw f_release_type ;3
dw f_send_pkt ;4
dw f_terminate ;5
dw f_get_address ;6
dw f_reset_interface ;7
dw f_stop ;8
dw f_not_implemented ;9
dw f_get_parameters ;10
dw f_not_implemented ;11
dw f_as_send_pkt ;12
dw f_drop_pkt ;13
dw f_not_implemented ;14
dw f_not_implemented ;15
dw f_not_implemented ;16
dw f_not_implemented ;17
dw f_not_implemented ;18
dw f_not_implemented ;19
dw f_set_rcv_mode ;20
dw f_get_rcv_mode ;21
dw f_set_multicast_list ;22
dw f_get_multicast_list ;23
dw f_get_statistics ;24
dw f_set_address ;25
;external data supplied by device-dependent module:
extrn driver_class: byte
extrn driver_type: byte
extrn driver_name: byte
extrn driver_function: byte
extrn parameter_list: byte
extrn rcv_modes: word ;count of modes followed by mode handles.
;external code supplied by device-dependent module:
extrn send_pkt: near
extrn as_send_pkt: near
extrn drop_pkt: near
extrn set_address: near
extrn terminate: near
extrn reset_interface: near
extrn xmit: near
extrn recv: near
extrn etopen: near
extrn set_multicast_list: near
extrn timer_isr: near
per_handle struc
next_type dw ? ;points to the next type to look at.
in_use db 0 ;non-zero if this handle is in use.
packet_type db MAX_P_LEN dup(0);associated packet type.
packet_type_len dw 0 ;associated packet type length.
receiver dd 0 ;receiver handler.
receiver_sig db 8 dup(?) ;signature at the receiver handler.
class db ? ;interface class
per_handle ends
if next_type ne 0
error error here.
endif
handles per_handle MAX_HANDLE dup(<>)
end_handles label byte
public multicast_count, multicast_addrs, multicast_broad
multicast_count dw 0 ;count of stored multicast addresses.
multicast_broad db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh ; entry for broadcast
multicast_addrs db MAX_MULTICAST*EADDR_LEN dup(?)
;the device-dependent code reads the board's address from ROM in the
;initialization code.
public address_len, rom_address, my_address
address_len dw EADDR_LEN ;default to Ethernet.
rom_address db MAX_ADDR_LEN dup(?) ;our address in ROM.
my_address db MAX_ADDR_LEN dup(?) ;our current address.
rcv_mode_num dw 3
found_handle dw 0 ; temp, handle for our packet
receive_ptr dd 0 ; the pkt receive service routine
public send_head, send_tail
send_head dd 0 ; head of transmit queue
send_tail dd 0 ; tail of transmit queue
statistics_list label dword
packets_in dw ?,?
packets_out dw ?,?
bytes_in dw ?,?
bytes_out dw ?,?
errors_in dw ?,?
errors_out dw ?,?
packets_dropped dw ?,? ;dropped due to no type handler.
savespss label dword
savesp dw ? ;saved during the stack swap.
savess dw ?
public their_timer
their_timer dd 0 ;original owner of timer int
their_recv_isr dd 0 ;original owner of board int.
;
; The following structure is used to access the registers pushed by the
; packet driver interrupt handler. Don't change this structure without also
; changing the "bytes" structure given below.
;
regs struc ; stack offsets of incoming regs
_ES dw ?
_DS dw ?
_BP dw ?
_DI dw ?
_SI dw ?
_DX dw ?
_CX dw ?
_BX dw ?
_AX dw ?
_IP dw ?
_CS dw ?
_F dw ? ; flags, Carry flag is bit 0
regs ends
;
; bits in the _F register.
;
CY equ 0001h
EI equ 0200h
;
; This structure is a bytewise version of the "regs" structure above.
;
bytes struc ; stack offsets of incoming regs
dw ? ; es, ds, bp, di, si are 16 bits
dw ?
dw ?
dw ?
dw ?
_DL db ?
_DH db ?
_CL db ?
_CH db ?
_BL db ?
_BH db ?
_AL db ?
_AH db ?
bytes ends
public their_isr
their_isr dd 0 ; original owner of pkt driver int
public our_isr
our_isr:
jmp short our_isr_0 ;the required signature.
nop
db 'PKT DRVR',0
our_isr_open:
push ax ; save lots of registers
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
call etopen ; init the card
jc our_isr_no_init
mov si,offset rom_address ;copy their original address to
movseg es,ds
mov di,offset my_address ; their current address.
mov cx,MAX_ADDR_LEN/2
rep movsw
cmp rcv_modes+2[3*2],0 ;does mode 3 exist?
stc ;make sure we generate an error!
je our_isr_no_init ;no.
call rcv_modes+2[3*2] ; call it.
clc
our_isr_no_init:
pop es ; restore lots of registers
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov dh,CANT_RESET ; (actually can't initialize)
jc our_isr_error
or flagbyte,CALLED_ETOPEN ; remember this fact
jmp short our_isr_cont
our_isr_0:
assume ds:nothing
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
cld
mov bx,cs ;set up ds.
mov ds,bx
assume ds:code
mov bp,sp ;we use bp to access the original regs.
and _F[bp],not CY ;start by clearing the carry flag.
if 0
test _F[bp],EI ;were interrupt on?
jz our_isr_ei ;no, don't turn them back on.
sti ;yes, turn them back on.
our_isr_ei:
endif
test flagbyte,CALLED_ETOPEN ; have we initialized the card?
jz our_isr_open ; no
our_isr_cont:
mov bl,ah ;jump to the correct function.
xor bh,bh
cmp bx,25 ;only twenty five functions right now.
ja f_bad_command
add bx,bx ;*2
;
; The functions are called with all the original registers except
; BX, DH, and BP. They do not need to preserve any of them. If the
; function returns with cy clear, all is well. Otherwise dh=error number.
;
call functions[bx]
assume ds:nothing
jc our_isr_error
our_isr_return:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
our_isr_error:
assume ds:nothing
mov bp,sp ;we use bp to access the original regs.
mov _DH[bp],dh
or _F[bp],CY ;return their carry flag.
jmp short our_isr_return
f_bad_command:
assume ds:code
extrn bad_command_intercept: near
mov bx,_BX[bp]
call bad_command_intercept
mov _BX[bp],bx
mov _DX[bp],dx
jnc our_isr_return
jmp our_isr_error
public re_enable_interrupts
re_enable_interrupts:
; Possibly re-enable interrupts. We put this here so that other routines
; don't need to know how we put things on the stack.
test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
je re_enable_interrupts_1 ; No.
sti ; Yes, re-enable interrupts now.
re_enable_interrupts_1:
ret
f_not_implemented:
mov dh,BAD_COMMAND
stc
ret
f_driver_info:
; As of 1.08, the handle is optional, so we no longer verify it.
; call verify_handle
cmp _AL[bp],0ffh ; correct calling convention?
jne f_driver_info_1 ; ne = incorrect, fail
;For enhanced PD, if they call
cmp _BX[bp],offset handles ;with a handle, give them the
;class they think it is
jb default_handle
cmp _BX[bp],offset end_handles ;otherwise default to first class
jae default_handle
mov bx, _BX[bp]
cmp [bx].in_use,0 ;if it's not in use, it's bad.
je default_handle
mov al, [bx].class
mov _CH[bp], al
jmp short got_handle
default_handle:
mov al,driver_class
mov _CH[bp],al
got_handle:
mov _BX[bp],majver ;version
mov al,driver_type
cbw
mov _DX[bp],ax
mov _CL[bp],0 ;number zero.
mov _DS[bp],ds ; point to our name in their ds:si
mov _SI[bp],offset driver_name
mov al,driver_function
mov _AL[bp],al
clc
ret
f_driver_info_1:
stc
ret
f_set_rcv_mode:
call verify_handle
cmp cx,rcv_mode_num ;are we already using that mode?
je f_set_rcv_mode_4 ;yes, no need to check anything.
mov dx,bx ;remember our handle.
call count_handles ;is ours the only open handle?
cmp cl,1
jne f_set_rcv_mode_1 ;no, don't change the receive mode.
mov cx,_CX[bp] ;get the desired receive mode.
cmp cx,rcv_modes ;do they have this many modes?
jae f_set_rcv_mode_1 ;no - must be a bad mode for us.
mov bx,cx
add bx,bx ;we're accessing words, not bytes.
mov ax,rcv_modes[bx]+2 ;get the handler for this mode.
or ax,ax ;do they have one?
je f_set_rcv_mode_1 ;no - must be a bad mode for us.
mov rcv_mode_num,cx ;yes - remember the number and
call ax ; call it.
f_set_rcv_mode_4:
clc
ret
f_set_rcv_mode_1:
mov dh,BAD_MODE
stc
ret
f_get_rcv_mode:
call verify_handle
mov ax,rcv_mode_num ;return the current receive mode.
mov _AX[bp],ax
clc
ret
f_set_multicast_list:
;following instruction not needed because cx hasn't been changed.
; mov cx,_CX[bp] ;Tell them how much room they have.
;verify that they supplied an even number of EADDR's.
mov ax,cx
xor dx,dx
mov bx,EADDR_LEN
div bx
or dx,dx ;zero remainder?
jne f_set_multicast_list_2 ;no, we don't have an even number of
; addresses.
cmp ax,MAX_MULTICAST ;is this too many?
ja f_set_multicast_list_3 ;yes - return NO_SPACE
f_set_multicast_list_1:
mov multicast_count,ax ;remember the number of addresses.
movseg es,cs
mov di,offset multicast_addrs
push ds
mov ds,_ES[bp] ; get ds:si -> new list.
mov si,_DI[bp]
push cx
rep movsb
pop cx
pop ds
mov si,offset multicast_addrs
call set_multicast_list
ret
f_set_multicast_list_2:
mov dh,BAD_ADDRESS
stc
ret
f_set_multicast_list_3:
mov dh,NO_SPACE
stc
ret
f_get_multicast_list:
mov _ES[bp],ds ;return what we have remembered.
mov _DI[bp],offset multicast_addrs
mov ax,EADDR_LEN ;multiply the count by the length.
mul multicast_count
mov _CX[bp],ax ;because they want total bytes.
clc
ret
f_get_statistics:
call verify_handle ;just in case.
mov _DS[bp],ds
mov _SI[bp],offset statistics_list
clc
ret
access_type_class:
mov dh,NO_CLASS
stc
ret
access_type_type:
mov dh,NO_TYPE
stc
ret
access_type_number:
mov dh,NO_NUMBER
stc
ret
access_type_bad:
mov dh,ERR_BAD_TYPE
stc
ret
;register caller of pkt TYPE
f_access_type:
mov bx, offset driver_class
access_type_9:
mov al, [bx] ;get the next class.
inc bx
or al,al ;end of the list?
je access_type_class ;class failed (story of my life)
cmp _AL[bp],al ;our class?
jne access_type_9 ;no, try again
access_type_1:
cmp _BX[bp],-1 ;generic type?
je access_type_2 ;yes.
mov al,driver_type
cbw
cmp _BX[bp],ax ;our type?
jne access_type_type ;no.
access_type_2:
cmp _DL[bp],0 ;generic number?
je access_type_3
cmp _DL[bp],1 ;our number?
jne access_type_number
access_type_3:
cmp _CX[bp],MAX_P_LEN ;is the type length too long?
ja access_type_bad ;yes - can't be ours.
; now we do two things--look for an open handle, and check the existing
; handles to see if they're replicating a packet type.
mov bx,offset handles
xor dx,dx ;keep the free handle here.
access_type_4:
cmp [bx].in_use,0 ;is this handle in use?
je access_type_5 ;no.
mov al, _AL[bp] ;is this handle the same class as
cmp al, [bx].class ; they're want?
jne access_type_6 ;no.
mov cx,_CX[bp] ;same length type?
cmp cx,[bx].packet_type_len
jne access_type_6 ;no.
mov es,_DS[bp] ;get a pointer to their type
mov di,_SI[bp] ; from their ds:si to our es:di
lea si,[bx].packet_type
repe cmpsb
jne short access_type_6 ;go look at the next one.
mov dh,TYPE_INUSE ;a handle has been assigned for TYPE
stc ;and we can't assign another
ret
access_type_5: ;handle is not in use
mov dx,bx ;remember a free handle
access_type_6:
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles ;examined all handles?
jb access_type_4 ;no, continue.
mov bx,dx ;did we find a free handle?
or bx,bx
je access_type_space ;no - return error.
mov [bx].in_use,1 ;remember that we're using it.
mov ax,_DI[bp] ;remember the receiver type.
mov [bx].receiver.offs,ax
mov ax,_ES[bp]
mov [bx].receiver.segm,ax
push ds
mov ax,ds
mov es,ax
mov ds,_DS[bp] ;remember their type.
mov si,_SI[bp]
mov cx,_CX[bp]
mov es:[bx].packet_type_len,cx ; remember the TYPE length
lea di,[bx].packet_type
rep movsb
lds si,es:[bx].receiver ;copy the first 8 bytes
lea di,[bx].receiver_sig ; to the receiver signature.
mov cx,8/2
rep movsw
pop ds
mov al, _AL[bp]
mov [bx].class, al
mov _AX[bp],bx ;return the handle to them.
call sort_type_list ;keep the type_list sorted.
clc
ret
access_type_space:
mov dh,NO_SPACE
stc
ret
f_release_type:
call verify_handle ;mark this handle as being unused.
mov [bx].in_use,0
call sort_type_list ;keep the type_list sorted.
call count_handles ;All handles gone now?
cmp cl,0
jne f_release_type_1 ;no, don't change the receive mode.
if 0
cmp rcv_modes+2[3*2],0 ;does mode 3 exist?
je f_release_type_1 ;no.
mov rcv_mode_num,3 ;yes - remember the number and
call rcv_modes+2[3*2] ; call it.
endif
f_release_type_1:
clc
ret
type_list dw 0
sort_type_list:
;we get called after every call to f_access_type and f_release_type.
;we build a linked list out of per_handle entries, sorted by decreasing
; order of packet_type_len values.
mov type_list.next_type,0 ;there are none as yet.
mov bx,offset handles
sort_type_list_1:
cmp [bx].in_use,0 ;is this one in use?
je sort_type_list_2 ;yes.
;we do an insertion sort here, using si->current and di->next. We
;insert this newly found handle into the linked list just before the
;place where we find a packet_type_len that's not more specific than us.
mov di,offset type_list ;start with the head as the next.
mov ax,[bx].packet_type_len ;look for the first length <= ours.
jmp short sort_type_list_5 ;jump into the middle of the list.
sort_type_list_3:
or di,di ;are there no more to look at?
je sort_type_list_4 ;yes, insert it here.
cmp [di].packet_type_len,ax ;is this length less than ours?
jbe sort_type_list_4
sort_type_list_5:
mov si,di ;go to the next entry.
mov di,[si].next_type ;keep di pointing to the next one.
jmp sort_type_list_3
sort_type_list_4:
mov ax,[si].next_type
mov [bx].next_type,ax
mov [si].next_type,bx
;end of the insertion sort.
sort_type_list_2:
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles ;examined all handles?
jb sort_type_list_1
ret
f_send_pkt:
;ds:si -> buffer, cx = length
; XXX Should re-enable interrupts here, but some drivers are broken.
; Possibly re-enable interrupts.
; test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
; je f_send_pkt_1 ; No.
; sti ; Yes, re-enable interrupts now.
;f_send_pkt_1:
;following two instructions not needed because si and cx haven't been changed.
; mov si,_SI[bp]
; mov cx,_CX[bp] ; count of bytes in the packet.
add2 packets_out,1
add2 bytes_out,cx ;add up the received bytes.
mov ds,_DS[bp] ; address of buffer from caller's ds.
assume ds:nothing, es:nothing
; If -n option take Ethernet encapsulated Novell IPX packets (from BYU's
; PDSHELL) and change them to be IEEE 802.3 encapsulated.
EPROT_OFF equ EADDR_LEN*2
test cs:flagbyte,N_OPTION
jnz f_send_pkt_2
call send_pkt
ret
f_send_pkt_2:
cmp ds:[si].EPROT_OFF,3781h ; if not Novell (prot 8137)
jne f_send_pkt_3 ; don't tread on it
push ax ; get scratch reg
mov ax,[si].EPROT_OFF+4 ; get len
xchg ah,al
inc ax ; make even (rounding up)
and al,0feh
xchg ah,al
mov ds:[si].EPROT_OFF,ax ; save in prot field
pop ax ; restore old contents
f_send_pkt_3:
call send_pkt
ret
assume ds:code
f_as_send_pkt:
;es:di -> iocb.
test driver_function,4 ; is this a high-performance driver?
je f_as_send_pkt_2 ; no.
; Possibly re-enable interrupts.
test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
je f_as_send_pkt_1 ; No.
sti ; Yes, re-enable interrupts now.
f_as_send_pkt_1:
push ds ; set up proper ds for the buffer
lds si,es:[di].buffer ; ds:si -> buffer
assume ds:nothing
mov cx,es:[di].len ; cx = length
add2 packets_out,1
add2 bytes_out,cx ; add up the received bytes.
;ds:si -> buffer, cx = length, es:di -> iocb.
call as_send_pkt
pop ds
assume ds:code
ret
f_as_send_pkt_2:
mov dh, BAD_COMMAND ; return an error.
stc
ret
f_drop_pkt:
; es:di -> iocb.
test driver_function,4 ; is this a high-performance driver?
je f_as_send_pkt_2 ; no.
push ds ; Preserve ds
mov si,offset send_head ; Get head offset
dp_loop:
mov ax,ds:[si] ; Get offset
mov dx,ds:[si+2] ; Get segment
mov bx,ax
or bx,dx ; End of list?
je dp_endlist ; Yes
cmp ax,di ; Offsets equal?
jne dp_getnext ; No
mov bx,es
cmp dx,bx ; Segments equal?
jne dp_getnext ; No
call drop_pkt ; Pass to driver
les di,es:[di].next ; Get next segment:offset
mov ds:[si],di ; Set next offset
mov ds:[si+2],es ; Set next segment
pop ds ; Restore ds
clc
ret
dp_getnext:
mov ds,dx ; Get next segment
mov si,ax ; Get next iocb offset
lea si,ds:[si].next ; Get next iocb next ptr offset
jmp dp_loop ; Try again
dp_endlist:
pop ds ; Restore ds
mov dh,BAD_IOCB ; Return error
stc ; Set carry
ret
f_terminate:
call verify_handle ; must have a handle
mov [bx].in_use,0 ; mark handle as free
call count_handles ; all handles gone?
or cl,cl
jne f_terminate_4 ; no, can't exit completely
;
; Now disable interrupts
;
mov al,int_no
or al,al ;are they using a hardware interrupt?
je f_terminate_no_irq ;no.
cmp original_mask,0 ;was it enabled?
je f_terminate_no_mask ;yes, don't mask it now.
call maskint
f_terminate_no_mask:
;
; Now return the interrupt to their handler.
;
mov ah,25h ;get the old interrupt into es:bx
mov al,int_no
add al,8
cmp al,8+8 ;is it a slave 8259 interrupt?
jb f_terminate_3 ;no.
add al,70h - (8+8) ;map it to the real interrupt.
f_terminate_3:
push ds
lds dx,their_recv_isr
int 21h
pop ds
f_terminate_no_irq:
cmp their_timer.segm,0 ;did we hook the timer interrupt?
je f_terminate_no_timer
mov ax,2508h ;restore the timer interrupt.
push ds
lds dx,their_timer
int 21h
pop ds
f_terminate_no_timer:
call terminate ;terminate the hardware.
mov al,entry_point ;release our_isr.
mov ah,25h
push ds
lds dx,their_isr
int 21h
pop ds
;
; Now free our memory
;
movseg es,cs
mov ah,49h
int 21h
clc
ret
f_terminate_4:
mov dh, CANT_TERMINATE
stc
ret
f_get_address:
; call verify_handle
; mov es,_ES[bp] ; get new one
; mov di,_DI[bp] ; get pointer, es:di is ready
; mov cx,_CX[bp] ;Tell them how much room they have.
cmp cx,address_len ;is there enough room for our address?
jb get_address_space ;no.
mov cx,address_len ;yes - get our address length.
mov _CX[bp],cx ;Tell them how long our address is.
mov si,offset my_address ;copy it into their area.
rep movsb
clc
ret
get_address_space:
mov dh,NO_SPACE
stc
ret
f_set_address:
call count_handles
cmp cl,1 ;more than one handle in use?
ja f_set_address_inuse ;yes - we can't set the address
mov cx,_CX[bp] ;get the desired address length.
cmp ch,0
cmp cl,parameter_list[3] ;is it the right length?
ja f_set_address_too_long ;no.
mov ds,_ES[bp] ; set new one
assume ds:nothing
mov si,_DI[bp] ; set pointer, ds:si is ready
mov ax,cs
mov es,ax
mov di,offset my_address
rep movsb
mov ds,ax ;restore ds.
assume ds:code
mov cx,_CX[bp] ;get the desired address length.
mov si,offset my_address
call set_address
jc f_set_address_err ;Did it work?
mov cl,parameter_list[3]
xor ch,ch
mov _CX[bp],cx ;yes - return our address length.
clc
ret
f_set_address_inuse:
mov dh,CANT_SET
stc
ret
f_set_address_too_long:
mov dh,NO_SPACE
stc
ret
f_set_address_err:
;we get here with cy set - leave it set.
mov si,offset rom_address ;we can't set the address, restore
mov di,offset my_address ; to original.
mov cx,MAX_ADDR_LEN/2
rep movsw
ret
f_reset_interface:
call verify_handle
call reset_interface
clc
ret
; Stop the packet driver doing upcalls. Also a following terminate will
; always succed (no in use handles any longer).
f_stop:
mov bx,offset handles
f_stop_2:
mov [bx].in_use,0
add bx,(size per_handle) ; next handle
cmp bx,offset end_handles
jb f_stop_2
clc
ret
f_get_parameters:
;strictly speaking, this function only works for high-performance drivers.
test driver_function,4 ;is this a high-performance driver?
jne f_get_parameters_1 ;yes.
mov dh,BAD_COMMAND ;no - return an error.
stc
ret
f_get_parameters_1:
mov _ES[bp],cs
mov _DI[bp],offset parameter_list
clc
ret
count_handles:
;exit with cl = number of handles currently in use.
mov bx,offset handles
mov cl,0 ;number of handles in use.
count_handles_1:
add cl,[bx].in_use ;is this handle in use?
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles
jb count_handles_1
ret
verify_handle:
;Ensure that their handle is real. If it isn't, we pop off our return
;address, and return to *their* return address with cy set.
mov bx,_BX[bp] ;get the handle they gave us
cmp bx,offset handles
jb verify_handle_bad ;no - must be bad.
cmp bx,offset end_handles
jae verify_handle_bad ;no - must be bad.
cmp [bx].in_use,1 ;if it's not in use, it's bad.
jne verify_handle_bad
ret
verify_handle_bad:
mov dh,ERR_BAD_HANDLE
add sp,2 ;pop off our return address.
stc
ret
public set_recv_isr
set_recv_isr:
mov ah,35h ;get the old interrupt into es:bx
mov al,int_no ; board's interrupt vector
or al,al
je set_isr_no_irq
add al,8
cmp al,8+8 ;is it a slave 8259 interrupt?
jb set_recv_isr_1 ;no.
add al,70h - 8 - 8 ;map it to the real interrupt.
set_recv_isr_1:
int 21h
mov their_recv_isr.offs,bx ;remember the old seg:off.
mov their_recv_isr.segm,es
mov ah,25h ;now set our recv interrupt.
mov dx,offset recv_isr
int 21h
cmp byte ptr timer_isr,0cfh ;is there just an iret at their handler?
je set_isr_no_timer ;yes, don't bother hooking the timer.
mov ax,3508h ;get the old interrupt into es:bx
int 21h
mov their_timer.offs,bx ;remember the old seg:off.
mov their_timer.segm,es
mov ah,25h ;now set our recv interrupt.
mov dx,offset timer_isr
int 21h
set_isr_no_timer:
mov al,int_no ; Now enable interrupts
call unmaskint
mov original_mask,al