-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy path3c509.asm
1294 lines (1118 loc) · 36.6 KB
/
3c509.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
version equ 6
;History:1,1
;Fri Mar 08 14:48:42 2002 Merge in Peter Tattum's 3c509b changes.
;Mon Jan 22 15:09:36 1996 we were rejecting frames with dribble set and accepting other errored frames.
.8086
; Copyright, 1988-1992, 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
include defs.asm
code segment word public
assume cs:code, ds:code
;----------------------------------------------------------------------------;
; ;
; This source file is the property of 3Com Corporation and may not be ;
; copied or distributed in any isomorphic form without an appropriate ;
; prior licensing arrangement with 3Com Corporation. ;
; ;
; Copyright (c) 1988 3Com Corporation ;
; ;
;------ Equates -------------------------------------------------------------;
;
; Command code masks
;
CMD_CMDMASK equ 0F800h ; command bits
CMD_ARGMASK equ 007FFh ; argument bits
;
; Command codes, word form
;
CMD_GLOBALRESET equ 00000b shl 11 ; global reset
CMD_SELECTWINDOW equ 00001B shl 11 ; select register window
CMD_STARTINTXCVR equ 00010b shl 11 ; start internal transciver
CMD_RXDISABLE equ 00011b shl 11 ; rx disable
CMD_RXENABLE equ 00100b shl 11 ; rx enable
CMD_RXRESET equ 00101b shl 11 ; rx reset
CMD_RXDISCARD equ 01000b shl 11 ; rx discard top packet
CMD_TXENABLE equ 01001b shl 11 ; tx enable
CMD_TXDISABLE equ 01010b shl 11 ; tx disable
CMD_TXRESET equ 01011b shl 11 ; tx reset
CMD_REQUESTINT equ 01100b shl 11 ; request interrupt
CMD_ACKNOWLEDGE equ 01101b shl 11 ; acknowledge interrupt
CMD_SETINTMASK equ 01110b shl 11 ; set interrupt mask
CMD_SETRZMASK equ 01111b shl 11 ; set read zero mask
CMD_SETRXFILTER equ 10000b shl 11 ; set rx filter
CMD_SETRXEARLY equ 10001b shl 11 ; set rx early threshold
CMD_SETTXAVAILABLE equ 10010b shl 11 ; set tx available threshold
CMD_SETTXSTART equ 10011b shl 11 ; set tx start threshold
CMD_STATSENABLE equ 10101b shl 11 ; statistics enable
CMD_STATSDISABLE equ 10110b shl 11 ; statistics disable
CMD_STOPINTXCVR equ 10111b shl 11 ; start internal transciver
;
; Command codes, hibyte form (commands without operands only)
;
CMDH_STARTINTXCVR equ CMD_STARTINTXCVR shr 8
CMDH_RXDISABLE equ CMD_RXDISABLE shr 8
CMDH_RXENABLE equ CMD_RXENABLE shr 8
CMDH_RXDISCARD equ CMD_RXDISCARD shr 8
CMDH_TXENABLE equ CMD_TXENABLE shr 8
CMDH_TXDISABLE equ CMD_TXDISABLE shr 8
CMDH_REQUESTINT equ CMD_REQUESTINT shr 8
CMDH_STATSENABLE equ CMD_STATSENABLE shr 8
CMDH_STATSDISABLE equ CMD_STATSDISABLE shr 8
CMDH_STOPINTXCVR equ CMD_STOPINTXCVR shr 8
;
; Status register bits (INT for interrupt sources, ST for the rest)
;
INT_LATCH equ 00001h ; interrupt latch
INT_ADAPTERFAIL equ 00002h ; adapter failure
INT_TXCOMPLETE equ 00004h ; tx complete
INT_TXAVAILABLE equ 00008h ; tx available
INT_RXCOMPLETE equ 00010h ; rx complete
INT_RXEARLY equ 00020h ; rx early
INT_REQUESTED equ 00040h ; interrupt requested
INT_UPDATESTATS equ 00080h ; update statistics
ST_FAILED equ 00800h ; command failed
ST_BUSY equ 01000h ; command busy
ST_WINDOW equ 0E000h ; window bits (13-15)
STH_FAILED equ ST_FAILED shr 8
STH_BUSY equ ST_BUSY shr 8
STH_WINDOW equ ST_WINDOW shr 8
;
; RxStatus register bits
;
RXS_INCOMPLETE equ 8000h ; not completely received
RXS_ERROR equ 4000h ; error in packet
RXS_LENGTH equ 07FFh ; bytes in RxFIFO
RXS_ERRTYPE equ 3800h ; Rx error type, bit 13-11
RXS_OVERRUN equ 0000h ; overrun error
RXS_OVERSIZE equ 0800h ; oversize packet error
RXS_DRIBBLE equ 1000h ; dribble bit (not an error)
RXS_RUNT equ 1800h ; runt packet error
RXS_CRC equ 2800h ; CRC error
RXS_FRAMING equ 2000h ; framing error
RXSH_INCOMPLETE equ RXS_INCOMPLETE shr 8
RXSH_ERROR equ RXS_ERROR shr 8
RXSH_ERRTYPE equ RXS_ERRTYPE shr 8
RXSH_OVERRUN equ RXS_OVERRUN shr 8
RXSH_DRIBBLE equ RXS_DRIBBLE shr 8
RXSH_CRC equ RXS_CRC shr 8
RXSH_RUNT equ RXS_RUNT shr 8
RXSH_OVERSIZE equ RXS_OVERSIZE shr 8
RXSH_FRAMING equ RXS_FRAMING shr 8
;
; TxStatus register bits
;
TXS_COMPLETE equ 80h ; tx completed
TXS_INTREQUESTED equ 40h ; interrupt on successfull tx
TXS_ERRTYPE equ 38h ; error bits
TXS_JABBERERROR equ 20h ; jabber error
TXS_UNDERRUN equ 10h ; tx underrun error
TXS_MAXCOLLISIONS equ 08h ; max collisions error
TXS_STATUSOVERFLOW equ 04h ; TX status stack is full
;
; Window Numbers
;
WNO_SETUP equ 0 ; setup/configuration
WNO_OPERATING equ 1 ; operating set
WNO_STATIONADDRESS equ 2 ; station address setup/read
WNO_FIFO equ 3 ; FIFO management
WNO_DIAGNOSTICS equ 4 ; diagnostics
WNO_READABLE equ 5 ; registers set by commands
WNO_STATISTICS equ 6 ; statistics
;
; Port offsets, Window 1 (WNO_OPERATING)
;
PORT_CmdStatus equ 0Eh ; command/status
PORT_TxFree equ 0Ch ; free transmit bytes
PORT_TxStatus equ 0Bh ; transmit status (byte)
PORT_Timer equ 0Ah ; latency timer (byte)
PORT_RxStatus equ 08h ; receive status
PORT_RxFIFO equ 00h ; RxFIFO read
PORT_TxFIFO equ 00h ; TxFIFO write
;
; Port offsets, Window 0 (WNO_SETUP)
;
PORT_EEData equ 0Ch ; EEProm data register
PORT_EECmd equ 0Ah ; EEProm command register
PORT_CfgResource equ 08h ; resource configuration
PORT_CfgAddress equ 06h ; address configuration
PORT_CfgControl equ 04h ; configuration control
PORT_ProductID equ 02h ; product id (EISA)
PORT_Manufacturer equ 00h ; Manufacturer code (EISA)
;
; Port offsets, Window 2 (WNO_STATIONADDRESS)
;
PORT_SA0_1 equ 00h ; station address bytes 0,1
PORT_SA2_3 equ 02h ; station address bytes 2,3
PORT_SA4_5 equ 04h ; station address bytes 4,5
;
; Port offsets, Window 3 (WNO_FIFO)
;
PORT_ALT_TxFree equ 0Ch ; free transmit bytes (dup)
PORT_RxFree equ 0Ah ; free receive bytes
;
; Port offsets, Window 4 (WNO_DIAGNOSTICS)
;
PORT_MediaStatus equ 0Ah ; media type/status
PORT_SlingshotStatus equ 08h ; Slingshot status
PORT_NetDiagnostic equ 06h ; net diagnostic
PORT_FIFODiagnostic equ 04h ; FIFO diagnostic
PORT_HostDiagnostic equ 02h ; host diagnostic
PORT_TxDiagnostic equ 00h ; tx diagnostic
;
; Port offsets, Window 5 (WNO_READABLE)
;
PORT_RZMask equ 0Ch ; read zero mask
PORT_IntMask equ 0Ah ; interrupt mask
PORT_RxFilter equ 08h ; receive filter
PORT_RxEarly equ 06h ; rx early threshold
PORT_TxAvailable equ 02h ; tx available threshold
PORT_TxStart equ 00h ; tx start threshold
;
; Port offsets, Window 6 (WNO_STATISTICS)
;
PORT_TXBYTES equ 0Ch ; tx bytes ok
PORT_RXBYTES equ 0Ah ; rx bytes ok
PORT_TXDEFER equ 08h ; tx frames deferred (byte)
PORT_RXFRAMES equ 07h ; rx frames ok (byte)
PORT_TXFRAMES equ 06h ; tx frames ok (byte)
PORT_RXDISCARDED equ 05h ; rx frames discarded (byte)
PORT_TXLATE equ 04h ; tx frames late coll. (byte)
PORT_TXSINGLE equ 03h ; tx frames one coll. (byte)
PORT_TXMULTIPLE equ 02h ; tx frames mult. coll. (byte)
PORT_TXNOCD equ 01h ; tx frames no CDheartbt (byte)
PORT_TXCARRIERLOST equ 00h ; tx frames carrier lost (byte)
;
; Various command arguments
;
INT_ALLDISABLED equ 00000000000b ; all interrupts disabled
INT_ALLENABLED equ 00011111110b ; all interrupts enabled
FILTER_INDIVIDUAL equ 0001b ; individual address
FILTER_MULTICAST equ 0010b ; multicast/group addresses
FILTER_BROADCAST equ 0100b ; broadcast address
FILTER_PROMISCUOUS equ 1000b ; promiscuous mode
RXEARLY_DISABLED equ 2032 ; RxEarly to disable
TXAVAIL_DISABLED equ 2040 ; TxAvailable to disable
TXAVAIL_MIN equ 4
TXSTART_DISABLED equ 2040 ; TxStart to disable
TXSTART_MIN equ 0
TXSTART_MAX equ TXSTART_DISABLED
RXLENGTH_MAX equ 1792 ; maximum rxlength
;
; Transmit Preamble
;
PREAMBLESIZE equ 4 ; transmit preamble size
TXP_INTONSUCCESS equ 8000h ; interrupt on successful tx
;
; Bits in various diagnostics registers
;
MEDIA_TP equ 8000h ; TP transciever
MEDIA_BNC equ 4000h ; Thinnet transciever
MEDIA_INTENDEC equ 2000h ; internal encoder/decoder
MEDIA_SQE equ 1000h ; SQE present
MEDIA_LBEAT equ 0800h ; link beat ok (TP)
MEDIA_POLARITY equ 0400h ; polarity (TP)
MEDIA_JABBER equ 0200h ; jabber (TP)
MEDIA_UNSQUELCH equ 0100h ; unsquelch (TP)
MEDIA_LBEATENABLE equ 0080h ; link beat enable (TP)
MEDIA_JABBERENABLE equ 0040h ; jabber enable (TP)
MEDIA_CRS equ 0020h ; carrier sense
MEDIA_COLLISION equ 0010h ; collision
MEDIA_SQEENABLE equ 0008h ; enable SQE statistics
NETD_EXTLOOPBACK equ 8000h ; TP external loopback
NETD_ENDECLOOPBACK equ 4000h ; ENDEC loopback
NETD_CORELOOPBACK equ 2000h ; ethernet core loopback
NETD_FIFOLOOPBACK equ 1000h ; FIFO loopback
NETD_TXENABLED equ 0800h ; tx enabled
NETD_RXENABLED equ 0400h ; rx enabled
NETD_TXTRANSMITTING equ 0200h ; tx transmitting
NETD_TXRESETREQD equ 0100h ; tx reset required
FIFOD_RXRECEIVING equ 8000h ; rx receiveing
FIFOD_RXUNDERRUN equ 2000h ; rx underrun
FIFOD_RXSTATUSOVER equ 1000h ; rx status overrun
FIFOD_RXOVERRUN equ 0800h ; rx overrun
FIFOD_TXOVERRUN equ 0400h ; tx overrun
FIFOD_BISTRESULTS equ 00FFh ; BIST results (mask)
SLING_TXUNDERRUN equ 2000h ; Slingshot TxUnderrun bit
;
; board identification codes, byte swapped in Rev 0
;
EISA_MANUFACTURER_ID equ 06D50h ; EISA manufacturer code
ISA_PRODUCT_ID equ 09050h ; Product ID for ISA board
PRODUCT_ID_MASK equ 0F0FFh ; Mask off revision nibble
;
; EEProm access
;
EE_BUSY equ 8000h ; EEProm busy bit in EECmd
EE_TCOM_NODE_ADDR_WORD0 equ 00h
EE_TCOM_NODE_ADDR_WORD1 equ 01h
EE_TCOM_NODE_ADDR_WORD2 equ 02h
EE_VULCAN_PROD_ID equ 03h
EE_MANUFACTURING_DATA equ 04h
EE_SERIAL_NUMBER_WORD0 equ 05h
EE_SERIAL_NUMBER_WORD1 equ 06h
EE_MANUFACTURER_CODE equ 07h
EE_ADDR_CONFIGURATION equ 08h
EE_RESOURCE_CONFIGURATION equ 09h
EE_OEM_NODE_ADDR_WORD0 equ 0Ah
EE_OEM_NODE_ADDR_WORD1 equ 0Bh
EE_OEM_NODE_ADDR_WORD2 equ 0Ch
EE_SOFTWARE_CONFIG_INFO equ 0Dh
EE_CWORD equ 0Eh
;
; contention logic
;
READ_EEPROM equ 080h
ID_GLOBAL_RESET equ 0C0h
SET_TAG_REGISTER equ 0D0h
TEST_TAG_REGISTER equ 0D8h
ACTIVATE_AND_SET_IO equ 0E0h
ACTIVATE_VULCAN equ 0FFh
;
; Resource Configuration Register bits
;
RCONFIG_IRQ equ 0F000h
;
; Address Configuration Register bits
;
ACONFIG_XCVR equ 0C000h
ACONFIG_IOBASE equ 0001Fh
IOBASE_EISA equ 0001Fh
TP_XCVR equ 00000h
BNC_XCVR equ 0C000h
AUI_XCVR equ 04000h
MIN_IO_BASE_ADDR equ 200h
MAX_IO_BASE_ADDR equ 3F0h
REGISTER_SET_SIZE equ 10h
;
; Software Configuration Register bits
;
SW_OPTIMIZE equ 0030h
SW_MAXCLI equ 3F00h
SW_LINKBEAT equ 4000h
;
; Possibilities for SW_OPTIMIZE
;
OPTIMIZE_DOS_CLIENT equ 0010h
OPTIMIZE_WINDOWS_CLIENT equ 0020h
OPTIMIZE_SERVER equ 0030h
;
; Configuration Control Register bits
;
ENABLE_ADAPTER equ 01h
setwin macro win
setport PORT_CmdStatus
mov ax,CMD_SELECTWINDOW+win
out dx,ax
endm
extrn is_eisa: byte ;=0 if ISA, =1 if EISA
extrn is_186: byte ;=0 if 808[68], =1 if 80[1234]86.
extrn is_386: byte ;=0 if 80[12]8[68], =1 if 80[34]86.
public int_no, io_addr
int_no db 0,0,0,0 ;must be four bytes long for get_number.
io_addr dw 0,0 ;must be four bytes long for get_number.
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK,IEEE8023,0 ;null terminated list of classes.
driver_type db 94
driver_name db '3c509',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver specification
db 9 ;minor rev of packet driver specification
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
int_num dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
public rcv_modes
rcv_modes dw 7 ;number of receive modes in our table.
dw 0 ;There is no mode zero
dw rcv_mode_1
dw rcv_mode_2
dw rcv_mode_3
dw 0 ;haven't set up perfect filtering yet.
dw rcv_mode_5
dw rcv_mode_6
include timeout.asm
public bad_command_intercept
bad_command_intercept:
;called with ah=command, unknown to the skeleton.
;exit with nc if okay, cy, dh=error if not.
mov dh,BAD_COMMAND
stc
ret
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
tx_reset:
push ax
push dx
loadport
setport PORT_CmdStatus
pushf
cli
mov ax,CMD_TXRESET
out dx,ax
tx_reset_1:
in ax,dx ;wait for the command to finish.
test ax,ST_BUSY
jne tx_reset_1
popf
mov ax,CMD_TXENABLE ;yes, re-enable the transmitter.
out dx,ax
pop dx
pop ax
ret
public send_pkt
send_pkt:
;enter with es:di->upcall routine, (0:0) if no upcall is desired.
; (only if the high-performance bit is set in driver_function)
;enter with ds:si -> packet, cx = packet length.
;if we're a high-performance driver, es:di -> upcall.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
cmp cx,GIANT ; Is this packet too large?
ja send_pkt_toobig
loadport
setport PORT_TxStatus ;get the previous transmit status.
in al,dx
setport PORT_CmdStatus
test al,TXS_UNDERRUN or TXS_JABBERERROR ;do we need to reset transmitter?
je send_pkt_0
call tx_reset
send_pkt_0:
; test al,TXS_COMPLETE
; je send_pkt_0_1
; out dx,al
;send_pkt_0_1:
test al,TXS_ERRTYPE ;any errors?
je send_pkt_3 ;no.
call count_out_err ;yes, count it.
mov ax,CMD_TXENABLE ;yes, re-enable the transmitter.
out dx,ax
send_pkt_3:
mov bx,cx ;adjust for the size of the preamble,
add bx,4 + 3 ;and round BX up to dword boundary.
and bx,not 3
setport PORT_TxFree ;wait for enough bytes in transmit buffer.
mov ax,18
call set_timeout
send_pkt_1:
in ax,dx
cmp ax,bx
jae send_pkt_2
call do_timeout
jne send_pkt_1
call tx_reset
mov dh,CANT_SEND ;timed out, can't send.
stc
ret
send_pkt_toobig:
mov dh,NO_SPACE
stc
ret
send_pkt_2:
sub bx,4 ;reduce by the size of the preamble.
setport PORT_TxFIFO
mov ax,cx ;output the count
out dx,ax ; (no interrupt requested)
out dx,ax ;output the second reserved word.
mov cx,bx ;output the rest of the packet.
; cmp is_386,0 ;can we output dwords?
; jne send_pkt_7 ;yes.
shr cx,1 ;output 16 bits at a time.
; rep outsw
;start 8086 code
send_8086:
lodsw
out dx,ax
loop send_8086
;end 8086 code
jmp short send_pkt_6
;send_pkt_7:
; .386
; shr cx,2 ;already rounded up.
; rep outsd ;output 32 bits at a time.
; .286
send_pkt_6:
clc
ret
public set_address
set_address:
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
assume ds:nothing
cmp cx,EADDR_LEN ;ensure that their address is okay.
je set_address_4
mov dh,BAD_ADDRESS
stc
jmp short set_address_done
set_address_4:
loadport
setwin WNO_STATIONADDRESS
setport PORT_SA0_1
set_address_1:
lodsb
out dx,al
inc dx
loop set_address_1
set_address_okay:
mov cx,EADDR_LEN ;return their address length.
clc
set_address_done:
push cs
pop ds
assume ds:code
loadport
setwin WNO_OPERATING
ret
;skip past the following two bytes while destroying BX.
skip2 macro
db 0bbh ;opcode of "mov bx,0000"
endm
rcv_mode_1:
mov al,0 ;receive nothing
skip2
rcv_mode_2:
mov al,1 ;receive individual address
skip2
rcv_mode_3:
mov al,5 ;receive individual address+broadcast
skip2
rcv_mode_5:
mov al,3 ;receive individual address+group addr(multicast)
skip2
rcv_mode_6:
mov al,8 ;receive all packets.
mov ah,CMD_SETRXFILTER shr 8 ;set receive filter
loadport
setport PORT_CmdStatus
out dx,ax
ret
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, ax = number of addresses,
; cx = number of bytes.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret
public terminate
terminate:
loadport
setport PORT_CmdStatus
mov ax,CMD_GLOBALRESET
out dx,ax
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
ret
;decide if we know this packet's type.
;enter with es:di -> packet type, dl = packet class.
;exit with nc if we know it, cy if not.
extrn recv_locate: near
;do the first upcall, get a pointer to the packet.
;enter with cx = packet length.
;exit with cx = packet length, es:di -> buffer for the packet.
extrn recv_found: near
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
extrn recv_find: near
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near
;call this routine to schedule a subroutine that gets run after the
;recv_isr. This is done by stuffing routine's address in place
;of the recv_isr iret's address. This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
extrn schedule_exiting: near
;recv_exiting jumps here to exit, after pushing the flags.
extrn recv_exiting_exit: near
extrn count_in_err: near
extrn count_out_err: near
ether_buff db EADDR_LEN dup(?)
db EADDR_LEN dup(?)
ether_type db 8 dup(?)
ETHER_BUFF_LEN equ $ - ether_buff
.erre (ETHER_BUFF_LEN and 3) eq 0 ;must be an even # of dwords.
early_bytes dw 0 ;the early byte gets the worm.
read_header:
;enter with dx -> PORT_RxFIFO
;exit with es:di -> packet type.
mov ax,ds
mov es,ax
mov di,offset ether_buff
mov cx,ETHER_BUFF_LEN/4
repinsd:
shl cx,1 ;*** this gets changed into "rep insd"
; rep insw ;*** "nop" on a 386 or 486.
;start 8086 code
l_rep:
in ax,dx
stosw
loop l_rep
;end 8086 code
mov di,offset ether_type
mov dl, BLUEBOOK ;assume bluebook Ethernet.
mov ax, es:[di]
xchg ah, al
cmp ax, 1500
ja read_header_1
inc di ;set di to 802.2 header
inc di
mov dl, IEEE8023
read_header_1:
ret
public recv
recv:
;called from the recv isr. All registers have been saved, ds=cs,
;our interrupt has been acknowledged, and our interrupts have been
;masked at the interrupt controller.
assume ds:code
recv_another:
loadport
setport PORT_CmdStatus
in ax,dx ;did we get a packet?
or ax,CMD_ACKNOWLEDGE
out dx,ax
setport PORT_RxStatus
test al,INT_RXCOMPLETE
jne recv_complete
test al,INT_RXEARLY ;are we getting it early?
jne recv_early
jmp recv_exit ;no.
recv_early:
in ax,dx ;get the amount we can read.
and ax,RXS_LENGTH
cmp ax,ETHER_BUFF_LEN ;do we have enough to read early?
jb recv_early_1 ;no, give up.
mov early_bytes,ETHER_BUFF_LEN
setport PORT_RxFIFO
call read_header
call recv_locate ;see if this is a type we want.
jnc recv_early_1 ;it is, just exit.
jmp recv_discard ;it isn't.
recv_early_1:
jmp recv_another
;yes, this is dead code. It's only in here to ensure that the setport macro
;has the right value.
setport PORT_RxStatus
recv_complete:
in ax,dx ;get the size.
test ax,RXS_ERROR ;any errors?
je recv_complete_2 ;no, it's fine.
and ax,RXS_ERRTYPE ;get just the error type bits.
cmp ax,RXS_DRIBBLE ;dribble is just a warning.
je recv_complete_1 ;if only dribble is set, that's okay.
recv_err:
call count_in_err
jmp recv_discard
recv_complete_1:
in ax,dx ;get the size again.
recv_complete_2:
;Put it on the receive queue
and ax,RXS_LENGTH
mov cx,ax
cmp early_bytes,0 ;did we read the header in already?
jne recv_complete_3 ;yes, we've already got it.
cmp cx,RUNT ;check legal packet size
jb recv_err
cmp cx,GIANT
ja recv_err
push cx
setport PORT_RxFIFO
call read_header
pop cx
push cx
call recv_find
pop cx
jmp short recv_complete_4
recv_complete_3:
add cx,early_bytes ;add in the early bytes we got.
cmp cx,RUNT ;check legal packet size
jb recv_err
cmp cx,GIANT
ja recv_err
push cx
call recv_found ;do the first upcall.
pop cx
recv_complete_4:
mov ax,es ;is this pointer null?
or ax,di
je recv_discard ;yes - just free the frame.
push es ;remember where the buffer pointer is.
push di
mov bx,cx ;save the count.
mov cx,ETHER_BUFF_LEN/2 ;move the data over.
mov si,offset ether_buff
rep movsw
loadport ;restore the I/O port.
setport PORT_RxFIFO
mov cx,bx ;restore the count.
sub cx,ETHER_BUFF_LEN ;but leave off what we've already copied.
; cmp is_386,0
; jne io_input_386
io_input_286:
push cx
shr cx,1
; rep insw
;start 8086 code
l_input:
in ax, dx
stosw
loop l_input
;end 8086 code
pop cx
jnc io_input_286_1 ;go if the count was even.
; insb ;get that last byte.
;start 8086 code
in al, dx
stosb
;end 8086 code
in al,dx ;and get the pad byte.
test cx,2 ;even number of words?
jne io_input_done ;no.
in ax,dx ;yes, get the pad word.
jmp short io_input_done
io_input_286_1:
test cx,2 ;odd number of words?
je io_input_done ;no.
in ax,dx ;yes, get the pad word.
jmp short io_input_done
;io_input_386:
; .386
; push eax
; push cx ;first, get all the full words.
; shr cx,2
; rep insd
; pop cx
; test cx,3 ;even number of dwords?
; je io_input_386_one_byte ;yes.
; in eax,dx ;no, get the partial word.
; test cx,2 ;a full word to be stored?
; je io_input_386_one_word
; stosw ;yes, store it,
; shr eax,16 ;and move over by a word.
;io_input_386_one_word:
; test cx,1 ;a full byte to be stored?
; je io_input_386_one_byte
; stosb ;yes, store it.
;io_input_386_one_byte:
; pop eax
; .286
io_input_done:
mov cx,bx ;restore the count.
pop si
pop ds
assume ds:nothing
call recv_copy ;tell them that we copied it.
mov ax,cs ;restore our ds.
mov ds,ax
assume ds:code
recv_discard:
loadport
setport PORT_CmdStatus
pushf
cli
mov ax,CMD_RXDISCARD
out dx,ax
recv_discard_1:
in ax,dx ;wait for the command to finish.
test ax,ST_BUSY
jne recv_discard_1
popf
mov early_bytes,0
jmp recv_another
recv_exit:
ret
public timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
iret
;any code after this will not be kept. Buffers used by the program, if any,
;are allocated from the memory between end_resident and end_free_mem.
public end_resident,end_free_mem
end_resident label byte
end_free_mem label byte
public usage_msg, mca_usage_msg
mca_usage_msg label byte
usage_msg db "usage: 3c509 [options] <packet_int_no> [id_port]",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for a 3c509, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Portions Copyright 1992, Crynwr Software",CR,LF
db "8088/8086 support by Nestor a.k.a. DistWave",CR,LF,'$'
no_isa_msg db CR,LF
db "No 3c509 found. Use a different id_port value. Default is 0x110.",CR,LF,'$'
reading_msg db "Reading EEPROM.",'$'
multiple_msg db "Multiple 3C509s found, specify i/o port",CR,LF,'$'
wrong_port_msg db "No 3C509 board found at specified i/o port",CR,LF,'$'
eisa_in_isa_msg db "EISA configured board in ISA slot",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
aui_xcvr_msg db "Using AUI transceiver",CR,LF,'$'
bnc_xcvr_msg db "Using BNC (10Base2) transceiver",CR,LF,'$'
tp_xcvr_msg db "Using Twisted Pair (10BaseT) transceiver",CR,LF,'$'
id_port_name db "ID port ",'$'
;called when you're ready to receive interrupts.
extrn set_recv_isr: near
;enter with si -> argument string, di -> dword to store.
;if there is no number, don't change the number.
extrn get_number: near
;enter with dx -> argument string, di -> dword to print.
extrn print_number: near
;-> the unique Ethernet address of the card. Filled in by the etopen routine.
extrn rom_address: byte
;-> current address. Normally the same as rom_address, unless changed
;by the set_address() call.
extrn my_address: byte
address_configuration dw ?
resource_configuration dw ?
is_10base2 db 0
is_10baseT db 0
id_port dw 110h,0
scratch dw 0,0 ;for multi-board support
board_number db 0
;print the character in al.
extrn chrout: near
;print a crlf
extrn crlf: near
;parse_args is called with si -> first parameter (CR if none).
public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
mov di,offset id_port
call get_number
clc
ret
public etopen
etopen:
;initialize the driver. Fill in rom_address with the assigned address of
;the board. Exit with nc if all went well, or cy, dx -> $ terminated error msg.
;if all is okay,
; cmp is_186,0 ;this version requires a 186 or better.
; jne etopen_1
; mov dx,offset needs_186_msg
; stc
; ret
;etopen_1:
; cmp is_386,0 ;can we do a real insd?
; je etopen_2
;overlay the repinsd routine with a real "rep insd;nop"
; mov word ptr repinsd+0,066h+0f3h*256
; mov word ptr repinsd+2,06dh+090h*256
;etopen_2:
cmp is_eisa,0
jne etopen_eisa
jmp etopen_isa
etopen_eisa:
mov cx,0fh
eisa_search:
mov dx,cx ;move it into the first nibble.
shl dx,12
or dx,0c80h
in ax,dx ;look for the manufacturer's ID
cmp ax,EISA_MANUFACTURER_ID
jne eisa_search_1
inc dx
inc dx
in ax,dx ;look for the product ID
and ax,PRODUCT_ID_MASK
cmp ax,ISA_PRODUCT_ID
je eisa_found
eisa_search_1:
loop eisa_search
jmp etopen_isa ;;; if it's not EISA-configured, try ISA.
eisa_found:
and dx,0f000h
mov io_addr,dx
loadport
setwin WNO_SETUP
setport PORT_CfgAddress
in ax,dx
mov address_configuration,ax
setport PORT_CfgResource
in ax,dx
mov resource_configuration,ax
setport PORT_EECmd